From c923e4b7f21e8b003d6888d04f383656437c3b30 Mon Sep 17 00:00:00 2001 From: Justine Pelletreau Date: Mon, 4 Apr 2022 12:55:23 +0200 Subject: [PATCH] V1 --- .gitignore | 3 + Dockerfile | 10 + README.md | 52 + data/notes.pickle | Bin 0 -> 20702 bytes docker-compose.yml | 20 + squipnotes.png | Bin 0 -> 26288 bytes src/app.py | 164 + src/classes.py | 57 + src/funcs.py | 167 + src/myvenv/bin/Activate.ps1 | 247 + src/myvenv/bin/activate | 69 + src/myvenv/bin/activate.csh | 26 + src/myvenv/bin/activate.fish | 66 + src/myvenv/bin/flask | 8 + src/myvenv/bin/pip | 8 + src/myvenv/bin/pip3 | 8 + src/myvenv/bin/pip3.10 | 8 + src/myvenv/bin/python | 1 + src/myvenv/bin/python3 | 1 + src/myvenv/bin/python3.10 | 1 + .../Flask-2.0.3.dist-info/INSTALLER | 1 + .../Flask-2.0.3.dist-info/LICENSE.rst | 28 + .../Flask-2.0.3.dist-info/METADATA | 125 + .../Flask-2.0.3.dist-info/RECORD | 52 + .../Flask-2.0.3.dist-info/REQUESTED | 0 .../site-packages/Flask-2.0.3.dist-info/WHEEL | 5 + .../Flask-2.0.3.dist-info/entry_points.txt | 2 + .../Flask-2.0.3.dist-info/top_level.txt | 1 + .../Jinja2-3.0.3.dist-info/INSTALLER | 1 + .../Jinja2-3.0.3.dist-info/LICENSE.rst | 28 + .../Jinja2-3.0.3.dist-info/METADATA | 113 + .../Jinja2-3.0.3.dist-info/RECORD | 58 + .../Jinja2-3.0.3.dist-info/WHEEL | 5 + .../Jinja2-3.0.3.dist-info/entry_points.txt | 3 + .../Jinja2-3.0.3.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 | 6 + .../MarkupSafe-2.1.1.dist-info/top_level.txt | 1 + .../Werkzeug-2.0.3.dist-info/INSTALLER | 1 + .../Werkzeug-2.0.3.dist-info/LICENSE.rst | 28 + .../Werkzeug-2.0.3.dist-info/METADATA | 129 + .../Werkzeug-2.0.3.dist-info/RECORD | 111 + .../Werkzeug-2.0.3.dist-info/WHEEL | 5 + .../Werkzeug-2.0.3.dist-info/top_level.txt | 1 + .../site-packages/_distutils_hack/__init__.py | 128 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 5140 bytes .../__pycache__/override.cpython-310.pyc | Bin 0 -> 246 bytes .../site-packages/_distutils_hack/override.py | 1 + .../click-8.0.4.dist-info/INSTALLER | 1 + .../click-8.0.4.dist-info/LICENSE.rst | 28 + .../click-8.0.4.dist-info/METADATA | 111 + .../click-8.0.4.dist-info/RECORD | 41 + .../site-packages/click-8.0.4.dist-info/WHEEL | 5 + .../click-8.0.4.dist-info/top_level.txt | 1 + .../site-packages/click/__init__.py | 75 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 2703 bytes .../click/__pycache__/_compat.cpython-310.pyc | Bin 0 -> 15764 bytes .../__pycache__/_termui_impl.cpython-310.pyc | Bin 0 -> 16088 bytes .../__pycache__/_textwrap.cpython-310.pyc | Bin 0 -> 1563 bytes .../__pycache__/_unicodefun.cpython-310.pyc | Bin 0 -> 2330 bytes .../__pycache__/_winconsole.cpython-310.pyc | Bin 0 -> 7681 bytes .../click/__pycache__/core.cpython-310.pyc | Bin 0 -> 89082 bytes .../__pycache__/decorators.cpython-310.pyc | Bin 0 -> 14326 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 10211 bytes .../__pycache__/formatting.cpython-310.pyc | Bin 0 -> 9476 bytes .../click/__pycache__/globals.cpython-310.pyc | Bin 0 -> 2448 bytes .../click/__pycache__/parser.cpython-310.pyc | Bin 0 -> 13691 bytes .../shell_completion.cpython-310.pyc | Bin 0 -> 16558 bytes .../click/__pycache__/termui.cpython-310.pyc | Bin 0 -> 26811 bytes .../click/__pycache__/testing.cpython-310.pyc | Bin 0 -> 15206 bytes .../click/__pycache__/types.cpython-310.pyc | Bin 0 -> 32892 bytes .../click/__pycache__/utils.cpython-310.pyc | Bin 0 -> 17996 bytes .../python3.10/site-packages/click/_compat.py | 626 ++ .../site-packages/click/_termui_impl.py | 717 ++ .../site-packages/click/_textwrap.py | 49 + .../site-packages/click/_unicodefun.py | 100 + .../site-packages/click/_winconsole.py | 279 + .../python3.10/site-packages/click/core.py | 2953 ++++++ .../site-packages/click/decorators.py | 436 + .../site-packages/click/exceptions.py | 287 + .../site-packages/click/formatting.py | 301 + .../python3.10/site-packages/click/globals.py | 68 + .../python3.10/site-packages/click/parser.py | 529 ++ .../python3.10/site-packages/click/py.typed | 0 .../site-packages/click/shell_completion.py | 581 ++ .../python3.10/site-packages/click/termui.py | 806 ++ .../python3.10/site-packages/click/testing.py | 479 + .../python3.10/site-packages/click/types.py | 1049 ++ .../python3.10/site-packages/click/utils.py | 588 ++ .../site-packages/distutils-precedence.pth | 1 + .../site-packages/flask/__init__.py | 46 + .../site-packages/flask/__main__.py | 3 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1894 bytes .../__pycache__/__main__.cpython-310.pyc | Bin 0 -> 225 bytes .../flask/__pycache__/app.cpython-310.pyc | Bin 0 -> 63165 bytes .../__pycache__/blueprints.cpython-310.pyc | Bin 0 -> 21629 bytes .../flask/__pycache__/cli.cpython-310.pyc | Bin 0 -> 27289 bytes .../flask/__pycache__/config.cpython-310.pyc | Bin 0 -> 11701 bytes .../flask/__pycache__/ctx.cpython-310.pyc | Bin 0 -> 15568 bytes .../__pycache__/debughelpers.cpython-310.pyc | Bin 0 -> 6500 bytes .../flask/__pycache__/globals.cpython-310.pyc | Bin 0 -> 1804 bytes .../flask/__pycache__/helpers.cpython-310.pyc | Bin 0 -> 27442 bytes .../flask/__pycache__/logging.cpython-310.pyc | Bin 0 -> 2465 bytes .../__pycache__/scaffold.cpython-310.pyc | Bin 0 -> 24768 bytes .../__pycache__/sessions.cpython-310.pyc | Bin 0 -> 13617 bytes .../flask/__pycache__/signals.cpython-310.pyc | Bin 0 -> 2404 bytes .../__pycache__/templating.cpython-310.pyc | Bin 0 -> 5545 bytes .../flask/__pycache__/testing.cpython-310.pyc | Bin 0 -> 9390 bytes .../flask/__pycache__/typing.cpython-310.pyc | Bin 0 -> 1428 bytes .../flask/__pycache__/views.cpython-310.pyc | Bin 0 -> 5035 bytes .../__pycache__/wrappers.cpython-310.pyc | Bin 0 -> 5045 bytes .../lib/python3.10/site-packages/flask/app.py | 2091 ++++ .../site-packages/flask/blueprints.py | 609 ++ .../lib/python3.10/site-packages/flask/cli.py | 999 ++ .../python3.10/site-packages/flask/config.py | 295 + .../lib/python3.10/site-packages/flask/ctx.py | 489 + .../site-packages/flask/debughelpers.py | 172 + .../python3.10/site-packages/flask/globals.py | 59 + .../python3.10/site-packages/flask/helpers.py | 836 ++ .../site-packages/flask/json/__init__.py | 363 + .../json/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 11584 bytes .../json/__pycache__/tag.cpython-310.pyc | Bin 0 -> 11003 bytes .../site-packages/flask/json/tag.py | 312 + .../python3.10/site-packages/flask/logging.py | 74 + .../python3.10/site-packages/flask/py.typed | 0 .../site-packages/flask/scaffold.py | 875 ++ .../site-packages/flask/sessions.py | 416 + .../python3.10/site-packages/flask/signals.py | 56 + .../site-packages/flask/templating.py | 165 + .../python3.10/site-packages/flask/testing.py | 298 + .../python3.10/site-packages/flask/typing.py | 49 + .../python3.10/site-packages/flask/views.py | 158 + .../site-packages/flask/wrappers.py | 167 + .../itsdangerous-2.1.1.dist-info/INSTALLER | 1 + .../itsdangerous-2.1.1.dist-info/LICENSE.rst | 28 + .../itsdangerous-2.1.1.dist-info/METADATA | 97 + .../itsdangerous-2.1.1.dist-info/RECORD | 23 + .../itsdangerous-2.1.1.dist-info/WHEEL | 5 + .../top_level.txt | 1 + .../site-packages/itsdangerous/__init__.py | 19 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 878 bytes .../__pycache__/_json.cpython-310.pyc | Bin 0 -> 933 bytes .../__pycache__/encoding.cpython-310.pyc | Bin 0 -> 1882 bytes .../__pycache__/exc.cpython-310.pyc | Bin 0 -> 3421 bytes .../__pycache__/serializer.cpython-310.pyc | Bin 0 -> 9705 bytes .../__pycache__/signer.cpython-310.pyc | Bin 0 -> 8473 bytes .../__pycache__/timed.cpython-310.pyc | Bin 0 -> 6470 bytes .../__pycache__/url_safe.cpython-310.pyc | Bin 0 -> 2706 bytes .../site-packages/itsdangerous/_json.py | 16 + .../site-packages/itsdangerous/encoding.py | 54 + .../site-packages/itsdangerous/exc.py | 107 + .../site-packages/itsdangerous/py.typed | 0 .../site-packages/itsdangerous/serializer.py | 295 + .../site-packages/itsdangerous/signer.py | 257 + .../site-packages/itsdangerous/timed.py | 233 + .../site-packages/itsdangerous/url_safe.py | 80 + .../site-packages/jinja2/__init__.py | 45 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1919 bytes .../__pycache__/_identifier.cpython-310.pyc | Bin 0 -> 1906 bytes .../__pycache__/async_utils.cpython-310.pyc | Bin 0 -> 2503 bytes .../__pycache__/bccache.cpython-310.pyc | Bin 0 -> 13361 bytes .../__pycache__/compiler.cpython-310.pyc | Bin 0 -> 54608 bytes .../__pycache__/constants.cpython-310.pyc | Bin 0 -> 1550 bytes .../jinja2/__pycache__/debug.cpython-310.pyc | Bin 0 -> 5459 bytes .../__pycache__/defaults.cpython-310.pyc | Bin 0 -> 1350 bytes .../__pycache__/environment.cpython-310.pyc | Bin 0 -> 53151 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 5549 bytes .../jinja2/__pycache__/ext.cpython-310.pyc | Bin 0 -> 26452 bytes .../__pycache__/filters.cpython-310.pyc | Bin 0 -> 50783 bytes .../__pycache__/idtracking.cpython-310.pyc | Bin 0 -> 11125 bytes .../jinja2/__pycache__/lexer.cpython-310.pyc | Bin 0 -> 20504 bytes .../__pycache__/loaders.cpython-310.pyc | Bin 0 -> 20473 bytes .../jinja2/__pycache__/meta.cpython-310.pyc | Bin 0 -> 3830 bytes .../__pycache__/nativetypes.cpython-310.pyc | Bin 0 -> 4909 bytes .../jinja2/__pycache__/nodes.cpython-310.pyc | Bin 0 -> 40340 bytes .../__pycache__/optimizer.cpython-310.pyc | Bin 0 -> 1970 bytes .../jinja2/__pycache__/parser.cpython-310.pyc | Bin 0 -> 27713 bytes .../__pycache__/runtime.cpython-310.pyc | Bin 0 -> 33126 bytes .../__pycache__/sandbox.cpython-310.pyc | Bin 0 -> 11984 bytes .../jinja2/__pycache__/tests.cpython-310.pyc | Bin 0 -> 6704 bytes .../jinja2/__pycache__/utils.cpython-310.pyc | Bin 0 -> 27392 bytes .../__pycache__/visitor.cpython-310.pyc | Bin 0 -> 3960 bytes .../site-packages/jinja2/_identifier.py | 6 + .../site-packages/jinja2/async_utils.py | 75 + .../site-packages/jinja2/bccache.py | 364 + .../site-packages/jinja2/compiler.py | 1957 ++++ .../site-packages/jinja2/constants.py | 20 + .../python3.10/site-packages/jinja2/debug.py | 259 + .../site-packages/jinja2/defaults.py | 48 + .../site-packages/jinja2/environment.py | 1661 ++++ .../site-packages/jinja2/exceptions.py | 166 + .../python3.10/site-packages/jinja2/ext.py | 879 ++ .../site-packages/jinja2/filters.py | 1824 ++++ .../site-packages/jinja2/idtracking.py | 318 + .../python3.10/site-packages/jinja2/lexer.py | 869 ++ .../site-packages/jinja2/loaders.py | 652 ++ .../python3.10/site-packages/jinja2/meta.py | 111 + .../site-packages/jinja2/nativetypes.py | 124 + .../python3.10/site-packages/jinja2/nodes.py | 1204 +++ .../site-packages/jinja2/optimizer.py | 47 + .../python3.10/site-packages/jinja2/parser.py | 1040 ++ .../python3.10/site-packages/jinja2/py.typed | 0 .../site-packages/jinja2/runtime.py | 1104 +++ .../site-packages/jinja2/sandbox.py | 428 + .../python3.10/site-packages/jinja2/tests.py | 255 + .../python3.10/site-packages/jinja2/utils.py | 854 ++ .../site-packages/jinja2/visitor.py | 92 + .../site-packages/markupsafe/__init__.py | 295 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 10644 bytes .../__pycache__/_native.cpython-310.pyc | Bin 0 -> 2014 bytes .../site-packages/markupsafe/_native.py | 63 + .../site-packages/markupsafe/_speedups.c | 320 + .../_speedups.cpython-310-x86_64-linux-gnu.so | Bin 0 -> 44224 bytes .../site-packages/markupsafe/_speedups.pyi | 9 + .../site-packages/markupsafe/py.typed | 0 .../pip-21.2.4.dist-info/INSTALLER | 1 + .../pip-21.2.4.dist-info/LICENSE.txt | 20 + .../pip-21.2.4.dist-info/METADATA | 92 + .../site-packages/pip-21.2.4.dist-info/RECORD | 795 ++ .../pip-21.2.4.dist-info/REQUESTED | 0 .../site-packages/pip-21.2.4.dist-info/WHEEL | 5 + .../pip-21.2.4.dist-info/entry_points.txt | 5 + .../pip-21.2.4.dist-info/top_level.txt | 1 + .../python3.10/site-packages/pip/__init__.py | 13 + .../python3.10/site-packages/pip/__main__.py | 31 + .../pip/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 639 bytes .../pip/__pycache__/__main__.cpython-310.pyc | Bin 0 -> 601 bytes .../site-packages/pip/_internal/__init__.py | 19 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 760 bytes .../__pycache__/build_env.cpython-310.pyc | Bin 0 -> 9143 bytes .../__pycache__/cache.cpython-310.pyc | Bin 0 -> 7764 bytes .../__pycache__/configuration.cpython-310.pyc | Bin 0 -> 10727 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 15299 bytes .../__pycache__/main.cpython-310.pyc | Bin 0 -> 584 bytes .../__pycache__/pyproject.cpython-310.pyc | Bin 0 -> 3457 bytes .../self_outdated_check.cpython-310.pyc | Bin 0 -> 4363 bytes .../__pycache__/wheel_builder.cpython-310.pyc | Bin 0 -> 8293 bytes .../site-packages/pip/_internal/build_env.py | 294 + .../site-packages/pip/_internal/cache.py | 287 + .../pip/_internal/cli/__init__.py | 4 + .../cli/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 280 bytes .../autocompletion.cpython-310.pyc | Bin 0 -> 5189 bytes .../__pycache__/base_command.cpython-310.pyc | Bin 0 -> 5987 bytes .../__pycache__/cmdoptions.cpython-310.pyc | Bin 0 -> 22346 bytes .../command_context.cpython-310.pyc | Bin 0 -> 1314 bytes .../cli/__pycache__/main.cpython-310.pyc | Bin 0 -> 1378 bytes .../__pycache__/main_parser.cpython-310.pyc | Bin 0 -> 2164 bytes .../cli/__pycache__/parser.cpython-310.pyc | Bin 0 -> 9951 bytes .../__pycache__/progress_bars.cpython-310.pyc | Bin 0 -> 7619 bytes .../__pycache__/req_command.cpython-310.pyc | Bin 0 -> 12148 bytes .../cli/__pycache__/spinners.cpython-310.pyc | Bin 0 -> 4954 bytes .../__pycache__/status_codes.cpython-310.pyc | Bin 0 -> 359 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 -> 3107 bytes .../__pycache__/cache.cpython-310.pyc | Bin 0 -> 6048 bytes .../__pycache__/check.cpython-310.pyc | Bin 0 -> 1579 bytes .../__pycache__/completion.cpython-310.pyc | Bin 0 -> 3142 bytes .../__pycache__/configuration.cpython-310.pyc | Bin 0 -> 8344 bytes .../__pycache__/debug.cpython-310.pyc | Bin 0 -> 6699 bytes .../__pycache__/download.cpython-310.pyc | Bin 0 -> 3996 bytes .../__pycache__/freeze.cpython-310.pyc | Bin 0 -> 2638 bytes .../commands/__pycache__/hash.cpython-310.pyc | Bin 0 -> 2154 bytes .../commands/__pycache__/help.cpython-310.pyc | Bin 0 -> 1317 bytes .../__pycache__/index.cpython-310.pyc | Bin 0 -> 4563 bytes .../__pycache__/install.cpython-310.pyc | Bin 0 -> 17769 bytes .../commands/__pycache__/list.cpython-310.pyc | Bin 0 -> 10068 bytes .../__pycache__/search.cpython-310.pyc | Bin 0 -> 5364 bytes .../commands/__pycache__/show.cpython-310.pyc | Bin 0 -> 8442 bytes .../__pycache__/uninstall.cpython-310.pyc | Bin 0 -> 3112 bytes .../__pycache__/wheel.cpython-310.pyc | Bin 0 -> 4857 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 -> 807 bytes .../__pycache__/base.cpython-310.pyc | Bin 0 -> 1916 bytes .../__pycache__/installed.cpython-310.pyc | Bin 0 -> 1254 bytes .../__pycache__/sdist.cpython-310.pyc | Bin 0 -> 3594 bytes .../__pycache__/wheel.cpython-310.pyc | Bin 0 -> 1591 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 -> 234 bytes .../__pycache__/collector.cpython-310.pyc | Bin 0 -> 15951 bytes .../package_finder.cpython-310.pyc | Bin 0 -> 28156 bytes .../index/__pycache__/sources.cpython-310.pyc | Bin 0 -> 7127 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 | 408 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 9958 bytes .../__pycache__/_distutils.cpython-310.pyc | Bin 0 -> 4662 bytes .../__pycache__/_sysconfig.cpython-310.pyc | Bin 0 -> 6245 bytes .../__pycache__/base.cpython-310.pyc | Bin 0 -> 1544 bytes .../pip/_internal/locations/_distutils.py | 169 + .../pip/_internal/locations/_sysconfig.py | 219 + .../pip/_internal/locations/base.py | 52 + .../site-packages/pip/_internal/main.py | 13 + .../pip/_internal/metadata/__init__.py | 48 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1845 bytes .../metadata/__pycache__/base.cpython-310.pyc | Bin 0 -> 9236 bytes .../__pycache__/pkg_resources.cpython-310.pyc | Bin 0 -> 6088 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 -> 268 bytes .../__pycache__/candidate.cpython-310.pyc | Bin 0 -> 1421 bytes .../__pycache__/direct_url.cpython-310.pyc | Bin 0 -> 7119 bytes .../format_control.cpython-310.pyc | Bin 0 -> 2760 bytes .../models/__pycache__/index.cpython-310.pyc | Bin 0 -> 1246 bytes .../models/__pycache__/link.cpython-310.pyc | Bin 0 -> 10174 bytes .../models/__pycache__/scheme.cpython-310.pyc | Bin 0 -> 1036 bytes .../__pycache__/search_scope.cpython-310.pyc | Bin 0 -> 3497 bytes .../selection_prefs.cpython-310.pyc | Bin 0 -> 1698 bytes .../__pycache__/target_python.cpython-310.pyc | Bin 0 -> 3455 bytes .../models/__pycache__/wheel.cpython-310.pyc | Bin 0 -> 4352 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 -> 256 bytes .../network/__pycache__/auth.cpython-310.pyc | Bin 0 -> 7501 bytes .../network/__pycache__/cache.cpython-310.pyc | Bin 0 -> 2903 bytes .../__pycache__/download.cpython-310.pyc | Bin 0 -> 5470 bytes .../__pycache__/lazy_wheel.cpython-310.pyc | Bin 0 -> 8376 bytes .../__pycache__/session.cpython-310.pyc | Bin 0 -> 10534 bytes .../network/__pycache__/utils.cpython-310.pyc | Bin 0 -> 1452 bytes .../__pycache__/xmlrpc.cpython-310.pyc | Bin 0 -> 2069 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 -> 204 bytes .../__pycache__/check.cpython-310.pyc | Bin 0 -> 3963 bytes .../__pycache__/freeze.cpython-310.pyc | Bin 0 -> 6317 bytes .../__pycache__/prepare.cpython-310.pyc | Bin 0 -> 14276 bytes .../_internal/operations/build/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 210 bytes .../__pycache__/metadata.cpython-310.pyc | Bin 0 -> 1162 bytes .../metadata_legacy.cpython-310.pyc | Bin 0 -> 1954 bytes .../build/__pycache__/wheel.cpython-310.pyc | Bin 0 -> 1141 bytes .../__pycache__/wheel_legacy.cpython-310.pyc | Bin 0 -> 2539 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 -> 268 bytes .../editable_legacy.cpython-310.pyc | Bin 0 -> 1337 bytes .../__pycache__/legacy.cpython-310.pyc | Bin 0 -> 3494 bytes .../install/__pycache__/wheel.cpython-310.pyc | Bin 0 -> 20435 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 -> 2608 bytes .../__pycache__/constructors.cpython-310.pyc | Bin 0 -> 11715 bytes .../req/__pycache__/req_file.cpython-310.pyc | Bin 0 -> 13493 bytes .../__pycache__/req_install.cpython-310.pyc | Bin 0 -> 21469 bytes .../req/__pycache__/req_set.cpython-310.pyc | Bin 0 -> 5847 bytes .../__pycache__/req_tracker.cpython-310.pyc | Bin 0 -> 4342 bytes .../__pycache__/req_uninstall.cpython-310.pyc | Bin 0 -> 18843 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 -> 204 bytes .../__pycache__/base.cpython-310.pyc | Bin 0 -> 1029 bytes .../pip/_internal/resolution/base.py | 18 + .../_internal/resolution/legacy/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 211 bytes .../__pycache__/resolver.cpython-310.pyc | Bin 0 -> 12111 bytes .../_internal/resolution/legacy/resolver.py | 453 + .../resolution/resolvelib/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 215 bytes .../__pycache__/base.cpython-310.pyc | Bin 0 -> 6595 bytes .../__pycache__/candidates.cpython-310.pyc | Bin 0 -> 18899 bytes .../__pycache__/factory.cpython-310.pyc | Bin 0 -> 18568 bytes .../found_candidates.cpython-310.pyc | Bin 0 -> 4833 bytes .../__pycache__/provider.cpython-310.pyc | Bin 0 -> 6814 bytes .../__pycache__/reporter.cpython-310.pyc | Bin 0 -> 3242 bytes .../__pycache__/requirements.cpython-310.pyc | Bin 0 -> 7473 bytes .../__pycache__/resolver.cpython-310.pyc | Bin 0 -> 7814 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 -> 199 bytes .../utils/__pycache__/_log.cpython-310.pyc | Bin 0 -> 1527 bytes .../utils/__pycache__/appdirs.cpython-310.pyc | Bin 0 -> 1331 bytes .../utils/__pycache__/compat.cpython-310.pyc | Bin 0 -> 1515 bytes .../compatibility_tags.cpython-310.pyc | Bin 0 -> 4131 bytes .../__pycache__/datetime.cpython-310.pyc | Bin 0 -> 522 bytes .../__pycache__/deprecation.cpython-310.pyc | Bin 0 -> 3047 bytes .../direct_url_helpers.cpython-310.pyc | Bin 0 -> 1839 bytes .../distutils_args.cpython-310.pyc | Bin 0 -> 1106 bytes .../__pycache__/encoding.cpython-310.pyc | Bin 0 -> 1312 bytes .../__pycache__/entrypoints.cpython-310.pyc | Bin 0 -> 1309 bytes .../__pycache__/filesystem.cpython-310.pyc | Bin 0 -> 5167 bytes .../__pycache__/filetypes.cpython-310.pyc | Bin 0 -> 811 bytes .../utils/__pycache__/glibc.cpython-310.pyc | Bin 0 -> 1621 bytes .../utils/__pycache__/hashes.cpython-310.pyc | Bin 0 -> 5023 bytes .../inject_securetransport.cpython-310.pyc | Bin 0 -> 976 bytes .../utils/__pycache__/logging.cpython-310.pyc | Bin 0 -> 9084 bytes .../utils/__pycache__/misc.cpython-310.pyc | Bin 0 -> 21688 bytes .../utils/__pycache__/models.cpython-310.pyc | Bin 0 -> 1841 bytes .../__pycache__/packaging.cpython-310.pyc | Bin 0 -> 2529 bytes .../__pycache__/parallel.cpython-310.pyc | Bin 0 -> 3040 bytes .../__pycache__/pkg_resources.cpython-310.pyc | Bin 0 -> 1709 bytes .../setuptools_build.cpython-310.pyc | Bin 0 -> 2975 bytes .../__pycache__/subprocess.cpython-310.pyc | Bin 0 -> 5731 bytes .../__pycache__/temp_dir.cpython-310.pyc | Bin 0 -> 6891 bytes .../__pycache__/unpacking.cpython-310.pyc | Bin 0 -> 6467 bytes .../utils/__pycache__/urls.cpython-310.pyc | Bin 0 -> 1543 bytes .../__pycache__/virtualenv.cpython-310.pyc | Bin 0 -> 3226 bytes .../utils/__pycache__/wheel.cpython-310.pyc | Bin 0 -> 5927 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 -> 522 bytes .../vcs/__pycache__/bazaar.cpython-310.pyc | Bin 0 -> 3010 bytes .../vcs/__pycache__/git.cpython-310.pyc | Bin 0 -> 11733 bytes .../vcs/__pycache__/mercurial.cpython-310.pyc | Bin 0 -> 4655 bytes .../__pycache__/subversion.cpython-310.pyc | Bin 0 -> 7965 bytes .../versioncontrol.cpython-310.pyc | Bin 0 -> 19468 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 + .../site-packages/pip/_vendor/__init__.py | 111 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 2917 bytes .../__pycache__/appdirs.cpython-310.pyc | Bin 0 -> 21191 bytes .../__pycache__/distro.cpython-310.pyc | Bin 0 -> 36651 bytes .../__pycache__/pyparsing.cpython-310.pyc | Bin 0 -> 237859 bytes .../_vendor/__pycache__/six.cpython-310.pyc | Bin 0 -> 27597 bytes .../site-packages/pip/_vendor/appdirs.py | 633 ++ .../pip/_vendor/cachecontrol/__init__.py | 11 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 557 bytes .../__pycache__/_cmd.cpython-310.pyc | Bin 0 -> 1588 bytes .../__pycache__/adapter.cpython-310.pyc | Bin 0 -> 3105 bytes .../__pycache__/cache.cpython-310.pyc | Bin 0 -> 1836 bytes .../__pycache__/compat.cpython-310.pyc | Bin 0 -> 764 bytes .../__pycache__/controller.cpython-310.pyc | Bin 0 -> 7785 bytes .../__pycache__/filewrapper.cpython-310.pyc | Bin 0 -> 2185 bytes .../__pycache__/heuristics.cpython-310.pyc | Bin 0 -> 4724 bytes .../__pycache__/serialize.cpython-310.pyc | Bin 0 -> 4231 bytes .../__pycache__/wrapper.cpython-310.pyc | Bin 0 -> 695 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 -> 301 bytes .../__pycache__/file_cache.cpython-310.pyc | Bin 0 -> 3359 bytes .../__pycache__/redis_cache.cpython-310.pyc | Bin 0 -> 1581 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 -> 283 bytes .../__pycache__/__main__.cpython-310.pyc | Bin 0 -> 462 bytes .../certifi/__pycache__/core.cpython-310.pyc | Bin 0 -> 1557 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 -> 1907 bytes .../__pycache__/big5freq.cpython-310.pyc | Bin 0 -> 27186 bytes .../__pycache__/big5prober.cpython-310.pyc | Bin 0 -> 1137 bytes .../chardistribution.cpython-310.pyc | Bin 0 -> 5747 bytes .../charsetgroupprober.cpython-310.pyc | Bin 0 -> 2236 bytes .../__pycache__/charsetprober.cpython-310.pyc | Bin 0 -> 3490 bytes .../codingstatemachine.cpython-310.pyc | Bin 0 -> 2909 bytes .../__pycache__/compat.cpython-310.pyc | Bin 0 -> 408 bytes .../__pycache__/cp949prober.cpython-310.pyc | Bin 0 -> 1144 bytes .../chardet/__pycache__/enums.cpython-310.pyc | Bin 0 -> 2591 bytes .../__pycache__/escprober.cpython-310.pyc | Bin 0 -> 2638 bytes .../chardet/__pycache__/escsm.cpython-310.pyc | Bin 0 -> 8385 bytes .../__pycache__/eucjpprober.cpython-310.pyc | Bin 0 -> 2442 bytes .../__pycache__/euckrfreq.cpython-310.pyc | Bin 0 -> 12070 bytes .../__pycache__/euckrprober.cpython-310.pyc | Bin 0 -> 1145 bytes .../__pycache__/euctwfreq.cpython-310.pyc | Bin 0 -> 27190 bytes .../__pycache__/euctwprober.cpython-310.pyc | Bin 0 -> 1145 bytes .../__pycache__/gb2312freq.cpython-310.pyc | Bin 0 -> 19114 bytes .../__pycache__/gb2312prober.cpython-310.pyc | Bin 0 -> 1153 bytes .../__pycache__/hebrewprober.cpython-310.pyc | Bin 0 -> 3030 bytes .../__pycache__/jisfreq.cpython-310.pyc | Bin 0 -> 22142 bytes .../__pycache__/jpcntx.cpython-310.pyc | Bin 0 -> 37649 bytes .../langbulgarianmodel.cpython-310.pyc | Bin 0 -> 47930 bytes .../langgreekmodel.cpython-310.pyc | Bin 0 -> 46120 bytes .../langhebrewmodel.cpython-310.pyc | Bin 0 -> 44569 bytes .../langhungarianmodel.cpython-310.pyc | Bin 0 -> 47890 bytes .../langrussianmodel.cpython-310.pyc | Bin 0 -> 61023 bytes .../__pycache__/langthaimodel.cpython-310.pyc | Bin 0 -> 44745 bytes .../langturkishmodel.cpython-310.pyc | Bin 0 -> 44586 bytes .../__pycache__/latin1prober.cpython-310.pyc | Bin 0 -> 4436 bytes .../mbcharsetprober.cpython-310.pyc | Bin 0 -> 2257 bytes .../mbcsgroupprober.cpython-310.pyc | Bin 0 -> 1140 bytes .../__pycache__/mbcssm.cpython-310.pyc | Bin 0 -> 18767 bytes .../sbcharsetprober.cpython-310.pyc | Bin 0 -> 3086 bytes .../sbcsgroupprober.cpython-310.pyc | Bin 0 -> 1709 bytes .../__pycache__/sjisprober.cpython-310.pyc | Bin 0 -> 2480 bytes .../universaldetector.cpython-310.pyc | Bin 0 -> 5834 bytes .../__pycache__/utf8prober.cpython-310.pyc | Bin 0 -> 1989 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 446 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 -> 203 bytes .../__pycache__/chardetect.cpython-310.pyc | Bin 0 -> 2702 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 -> 208 bytes .../__pycache__/languages.cpython-310.pyc | Bin 0 -> 7970 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 -> 451 bytes .../colorama/__pycache__/ansi.cpython-310.pyc | Bin 0 -> 3012 bytes .../__pycache__/ansitowin32.cpython-310.pyc | Bin 0 -> 7910 bytes .../__pycache__/initialise.cpython-310.pyc | Bin 0 -> 1698 bytes .../__pycache__/win32.cpython-310.pyc | Bin 0 -> 3958 bytes .../__pycache__/winterm.cpython-310.pyc | Bin 0 -> 4575 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 -> 1070 bytes .../__pycache__/compat.cpython-310.pyc | Bin 0 -> 31881 bytes .../__pycache__/database.cpython-310.pyc | Bin 0 -> 42624 bytes .../distlib/__pycache__/index.cpython-310.pyc | Bin 0 -> 17325 bytes .../__pycache__/locators.cpython-310.pyc | Bin 0 -> 38391 bytes .../__pycache__/manifest.cpython-310.pyc | Bin 0 -> 10238 bytes .../__pycache__/markers.cpython-310.pyc | Bin 0 -> 4428 bytes .../__pycache__/metadata.cpython-310.pyc | Bin 0 -> 26570 bytes .../__pycache__/resources.cpython-310.pyc | Bin 0 -> 11044 bytes .../__pycache__/scripts.cpython-310.pyc | Bin 0 -> 11113 bytes .../distlib/__pycache__/util.cpython-310.pyc | Bin 0 -> 52572 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 20151 bytes .../distlib/__pycache__/wheel.cpython-310.pyc | Bin 0 -> 27373 bytes .../pip/_vendor/distlib/_backport/__init__.py | 6 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 491 bytes .../__pycache__/misc.cpython-310.pyc | Bin 0 -> 1113 bytes .../__pycache__/shutil.cpython-310.pyc | Bin 0 -> 21550 bytes .../__pycache__/sysconfig.cpython-310.pyc | Bin 0 -> 15917 bytes .../__pycache__/tarfile.cpython-310.pyc | Bin 0 -> 62490 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 +++ .../site-packages/pip/_vendor/distro.py | 1230 +++ .../pip/_vendor/html5lib/__init__.py | 35 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1310 bytes .../__pycache__/_ihatexml.cpython-310.pyc | Bin 0 -> 13867 bytes .../__pycache__/_inputstream.cpython-310.pyc | Bin 0 -> 21686 bytes .../__pycache__/_tokenizer.cpython-310.pyc | Bin 0 -> 37378 bytes .../__pycache__/_utils.cpython-310.pyc | Bin 0 -> 4804 bytes .../__pycache__/constants.cpython-310.pyc | Bin 0 -> 161269 bytes .../__pycache__/html5parser.cpython-310.pyc | Bin 0 -> 88529 bytes .../__pycache__/serializer.cpython-310.pyc | Bin 0 -> 10751 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 -> 360 bytes .../_trie/__pycache__/_base.cpython-310.pyc | Bin 0 -> 1612 bytes .../_trie/__pycache__/py.cpython-310.pyc | Bin 0 -> 2275 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 -> 208 bytes .../alphabeticalattributes.cpython-310.pyc | Bin 0 -> 1338 bytes .../filters/__pycache__/base.cpython-310.pyc | Bin 0 -> 878 bytes .../inject_meta_charset.cpython-310.pyc | Bin 0 -> 1876 bytes .../filters/__pycache__/lint.cpython-310.pyc | Bin 0 -> 2584 bytes .../__pycache__/optionaltags.cpython-310.pyc | Bin 0 -> 2737 bytes .../__pycache__/sanitizer.cpython-310.pyc | Bin 0 -> 20042 bytes .../__pycache__/whitespace.cpython-310.pyc | Bin 0 -> 1384 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 -> 949 bytes .../__pycache__/genshi.cpython-310.pyc | Bin 0 -> 1561 bytes .../__pycache__/sax.cpython-310.pyc | Bin 0 -> 1468 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 -> 3340 bytes .../__pycache__/base.cpython-310.pyc | Bin 0 -> 11333 bytes .../__pycache__/dom.cpython-310.pyc | Bin 0 -> 9420 bytes .../__pycache__/etree.cpython-310.pyc | Bin 0 -> 11722 bytes .../__pycache__/etree_lxml.cpython-310.pyc | Bin 0 -> 13039 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 -> 3990 bytes .../__pycache__/base.cpython-310.pyc | Bin 0 -> 6951 bytes .../__pycache__/dom.cpython-310.pyc | Bin 0 -> 1722 bytes .../__pycache__/etree.cpython-310.pyc | Bin 0 -> 3480 bytes .../__pycache__/etree_lxml.cpython-310.pyc | Bin 0 -> 6567 bytes .../__pycache__/genshi.cpython-310.pyc | Bin 0 -> 1928 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 -> 855 bytes .../idna/__pycache__/codec.cpython-310.pyc | Bin 0 -> 2617 bytes .../idna/__pycache__/compat.cpython-310.pyc | Bin 0 -> 676 bytes .../idna/__pycache__/core.cpython-310.pyc | Bin 0 -> 9061 bytes .../idna/__pycache__/idnadata.cpython-310.pyc | Bin 0 -> 35684 bytes .../__pycache__/intranges.cpython-310.pyc | Bin 0 -> 1866 bytes .../__pycache__/package_data.cpython-310.pyc | Bin 0 -> 219 bytes .../__pycache__/uts46data.cpython-310.pyc | Bin 0 -> 145393 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 -> 1435 bytes .../__pycache__/_version.cpython-310.pyc | Bin 0 -> 226 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 1816 bytes .../msgpack/__pycache__/ext.cpython-310.pyc | Bin 0 -> 6324 bytes .../__pycache__/fallback.cpython-310.pyc | Bin 0 -> 26450 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 -> 598 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 454 bytes .../__pycache__/_manylinux.cpython-310.pyc | Bin 0 -> 7308 bytes .../__pycache__/_musllinux.cpython-310.pyc | Bin 0 -> 4620 bytes .../__pycache__/_structures.cpython-310.pyc | Bin 0 -> 2978 bytes .../__pycache__/markers.cpython-310.pyc | Bin 0 -> 9297 bytes .../__pycache__/requirements.cpython-310.pyc | Bin 0 -> 3983 bytes .../__pycache__/specifiers.cpython-310.pyc | Bin 0 -> 22196 bytes .../__pycache__/tags.cpython-310.pyc | Bin 0 -> 12239 bytes .../__pycache__/utils.cpython-310.pyc | Bin 0 -> 3583 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 12933 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 -> 321 bytes .../pep517/__pycache__/build.cpython-310.pyc | Bin 0 -> 3621 bytes .../pep517/__pycache__/check.cpython-310.pyc | Bin 0 -> 4585 bytes .../__pycache__/colorlog.cpython-310.pyc | Bin 0 -> 2972 bytes .../pep517/__pycache__/compat.cpython-310.pyc | Bin 0 -> 1317 bytes .../__pycache__/dirtools.cpython-310.pyc | Bin 0 -> 1363 bytes .../__pycache__/envbuild.cpython-310.pyc | Bin 0 -> 4403 bytes .../pep517/__pycache__/meta.cpython-310.pyc | Bin 0 -> 2968 bytes .../__pycache__/wrappers.cpython-310.pyc | Bin 0 -> 12091 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 -> 929 bytes .../__pycache__/_in_process.cpython-310.pyc | Bin 0 -> 9738 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 -> 99893 bytes .../__pycache__/py31compat.cpython-310.pyc | Bin 0 -> 668 bytes .../pip/_vendor/pkg_resources/py31compat.py | 23 + .../pip/_vendor/progress/__init__.py | 177 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 5725 bytes .../progress/__pycache__/bar.cpython-310.pyc | Bin 0 -> 2615 bytes .../__pycache__/counter.cpython-310.pyc | Bin 0 -> 1443 bytes .../__pycache__/spinner.cpython-310.pyc | Bin 0 -> 1336 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 -> 4020 bytes .../__pycache__/__version__.cpython-310.pyc | Bin 0 -> 563 bytes .../_internal_utils.cpython-310.pyc | Bin 0 -> 1315 bytes .../__pycache__/adapters.cpython-310.pyc | Bin 0 -> 16914 bytes .../requests/__pycache__/api.cpython-310.pyc | Bin 0 -> 6662 bytes .../requests/__pycache__/auth.cpython-310.pyc | Bin 0 -> 8105 bytes .../__pycache__/certs.cpython-310.pyc | Bin 0 -> 647 bytes .../__pycache__/compat.cpython-310.pyc | Bin 0 -> 1626 bytes .../__pycache__/cookies.cpython-310.pyc | Bin 0 -> 18707 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 5021 bytes .../requests/__pycache__/help.cpython-310.pyc | Bin 0 -> 2915 bytes .../__pycache__/hooks.cpython-310.pyc | Bin 0 -> 1002 bytes .../__pycache__/models.cpython-310.pyc | Bin 0 -> 24434 bytes .../__pycache__/packages.cpython-310.pyc | Bin 0 -> 516 bytes .../__pycache__/sessions.cpython-310.pyc | Bin 0 -> 19788 bytes .../__pycache__/status_codes.cpython-310.pyc | Bin 0 -> 4679 bytes .../__pycache__/structures.cpython-310.pyc | Bin 0 -> 4461 bytes .../__pycache__/utils.cpython-310.pyc | Bin 0 -> 23441 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 -> 614 bytes .../__pycache__/providers.cpython-310.pyc | Bin 0 -> 6486 bytes .../__pycache__/reporters.cpython-310.pyc | Bin 0 -> 2276 bytes .../__pycache__/resolvers.cpython-310.pyc | Bin 0 -> 14983 bytes .../__pycache__/structs.cpython-310.pyc | Bin 0 -> 7171 bytes .../pip/_vendor/resolvelib/compat/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 209 bytes .../collections_abc.cpython-310.pyc | Bin 0 -> 385 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 + .../site-packages/pip/_vendor/six.py | 998 ++ .../pip/_vendor/tenacity/__init__.py | 517 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 16382 bytes .../__pycache__/_asyncio.cpython-310.pyc | Bin 0 -> 2622 bytes .../__pycache__/_utils.cpython-310.pyc | Bin 0 -> 1235 bytes .../__pycache__/after.cpython-310.pyc | Bin 0 -> 1239 bytes .../__pycache__/before.cpython-310.pyc | Bin 0 -> 1117 bytes .../__pycache__/before_sleep.cpython-310.pyc | Bin 0 -> 1419 bytes .../tenacity/__pycache__/nap.cpython-310.pyc | Bin 0 -> 1207 bytes .../__pycache__/retry.cpython-310.pyc | Bin 0 -> 8437 bytes .../tenacity/__pycache__/stop.cpython-310.pyc | Bin 0 -> 4025 bytes .../__pycache__/tornadoweb.cpython-310.pyc | Bin 0 -> 1772 bytes .../tenacity/__pycache__/wait.cpython-310.pyc | Bin 0 -> 7969 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 -> 387 bytes .../tomli/__pycache__/_parser.cpython-310.pyc | Bin 0 -> 16341 bytes .../tomli/__pycache__/_re.cpython-310.pyc | Bin 0 -> 2431 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 -> 2197 bytes .../__pycache__/_collections.cpython-310.pyc | Bin 0 -> 10871 bytes .../__pycache__/_version.cpython-310.pyc | Bin 0 -> 221 bytes .../__pycache__/connection.cpython-310.pyc | Bin 0 -> 13346 bytes .../connectionpool.cpython-310.pyc | Bin 0 -> 24488 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 11002 bytes .../__pycache__/fields.cpython-310.pyc | Bin 0 -> 8193 bytes .../__pycache__/filepost.cpython-310.pyc | Bin 0 -> 2758 bytes .../__pycache__/poolmanager.cpython-310.pyc | Bin 0 -> 15210 bytes .../__pycache__/request.cpython-310.pyc | Bin 0 -> 5634 bytes .../__pycache__/response.cpython-310.pyc | Bin 0 -> 20935 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 -> 207 bytes .../_appengine_environ.cpython-310.pyc | Bin 0 -> 1387 bytes .../__pycache__/appengine.cpython-310.pyc | Bin 0 -> 8203 bytes .../__pycache__/ntlmpool.cpython-310.pyc | Bin 0 -> 3642 bytes .../__pycache__/pyopenssl.cpython-310.pyc | Bin 0 -> 15537 bytes .../securetransport.cpython-310.pyc | Bin 0 -> 21934 bytes .../contrib/__pycache__/socks.cpython-310.pyc | Bin 0 -> 5609 bytes .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 224 bytes .../__pycache__/bindings.cpython-310.pyc | Bin 0 -> 10735 bytes .../__pycache__/low_level.cpython-310.pyc | Bin 0 -> 9111 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 -> 321 bytes .../packages/__pycache__/six.cpython-310.pyc | Bin 0 -> 27672 bytes .../urllib3/packages/backports/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 218 bytes .../__pycache__/makefile.cpython-310.pyc | Bin 0 -> 1318 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 -> 606 bytes .../_implementation.cpython-310.pyc | Bin 0 -> 3309 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 -> 1117 bytes .../__pycache__/connection.cpython-310.pyc | Bin 0 -> 3465 bytes .../util/__pycache__/proxy.cpython-310.pyc | Bin 0 -> 1352 bytes .../util/__pycache__/queue.cpython-310.pyc | Bin 0 -> 1072 bytes .../util/__pycache__/request.cpython-310.pyc | Bin 0 -> 3480 bytes .../util/__pycache__/response.cpython-310.pyc | Bin 0 -> 2365 bytes .../util/__pycache__/retry.cpython-310.pyc | Bin 0 -> 15790 bytes .../util/__pycache__/ssl_.cpython-310.pyc | Bin 0 -> 11319 bytes .../__pycache__/ssltransport.cpython-310.pyc | Bin 0 -> 7442 bytes .../util/__pycache__/timeout.cpython-310.pyc | Bin 0 -> 8949 bytes .../util/__pycache__/url.cpython-310.pyc | Bin 0 -> 10692 bytes .../util/__pycache__/wait.cpython-310.pyc | Bin 0 -> 3101 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 + .../site-packages/pip/_vendor/vendor.txt | 22 + .../pip/_vendor/webencodings/__init__.py | 342 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 9754 bytes .../__pycache__/labels.cpython-310.pyc | Bin 0 -> 5244 bytes .../__pycache__/mklabels.cpython-310.pyc | Bin 0 -> 1949 bytes .../__pycache__/tests.cpython-310.pyc | Bin 0 -> 5051 bytes .../x_user_defined.cpython-310.pyc | Bin 0 -> 2600 bytes .../pip/_vendor/webencodings/labels.py | 231 + .../pip/_vendor/webencodings/mklabels.py | 59 + .../pip/_vendor/webencodings/tests.py | 153 + .../_vendor/webencodings/x_user_defined.py | 325 + .../lib/python3.10/site-packages/pip/py.typed | 4 + .../site-packages/pkg_resources/__init__.py | 3288 +++++++ .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 100050 bytes .../pkg_resources/_vendor/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 201 bytes .../__pycache__/appdirs.cpython-310.pyc | Bin 0 -> 20262 bytes .../__pycache__/pyparsing.cpython-310.pyc | Bin 0 -> 198835 bytes .../pkg_resources/_vendor/appdirs.py | 608 ++ .../_vendor/packaging/__about__.py | 27 + .../_vendor/packaging/__init__.py | 26 + .../__pycache__/__about__.cpython-310.pyc | Bin 0 -> 717 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 563 bytes .../__pycache__/_compat.cpython-310.pyc | Bin 0 -> 1163 bytes .../__pycache__/_structures.cpython-310.pyc | Bin 0 -> 2707 bytes .../__pycache__/_typing.cpython-310.pyc | Bin 0 -> 1519 bytes .../__pycache__/markers.cpython-310.pyc | Bin 0 -> 9204 bytes .../__pycache__/requirements.cpython-310.pyc | Bin 0 -> 4109 bytes .../__pycache__/specifiers.cpython-310.pyc | Bin 0 -> 20470 bytes .../__pycache__/tags.cpython-310.pyc | Bin 0 -> 17349 bytes .../__pycache__/utils.cpython-310.pyc | Bin 0 -> 1654 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 13034 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 -> 2909 bytes .../__pycache__/setup.cpython-310.pyc | Bin 0 -> 329 bytes .../data/my-test-package-source/setup.py | 6 + .../setuptools-58.1.0.dist-info/INSTALLER | 1 + .../setuptools-58.1.0.dist-info/LICENSE | 19 + .../setuptools-58.1.0.dist-info/METADATA | 119 + .../setuptools-58.1.0.dist-info/RECORD | 296 + .../setuptools-58.1.0.dist-info/REQUESTED | 0 .../setuptools-58.1.0.dist-info/WHEEL | 5 + .../entry_points.txt | 56 + .../setuptools-58.1.0.dist-info/top_level.txt | 3 + .../site-packages/setuptools/__init__.py | 242 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 8605 bytes .../_deprecation_warning.cpython-310.pyc | Bin 0 -> 562 bytes .../__pycache__/_imp.cpython-310.pyc | Bin 0 -> 2088 bytes .../__pycache__/archive_util.cpython-310.pyc | Bin 0 -> 5858 bytes .../__pycache__/build_meta.cpython-310.pyc | Bin 0 -> 9130 bytes .../__pycache__/config.cpython-310.pyc | Bin 0 -> 20918 bytes .../__pycache__/dep_util.cpython-310.pyc | Bin 0 -> 869 bytes .../__pycache__/depends.cpython-310.pyc | Bin 0 -> 5282 bytes .../__pycache__/dist.cpython-310.pyc | Bin 0 -> 36265 bytes .../__pycache__/errors.cpython-310.pyc | Bin 0 -> 862 bytes .../__pycache__/extension.cpython-310.pyc | Bin 0 -> 1958 bytes .../__pycache__/glob.cpython-310.pyc | Bin 0 -> 3747 bytes .../__pycache__/installer.cpython-310.pyc | Bin 0 -> 2765 bytes .../__pycache__/launch.cpython-310.pyc | Bin 0 -> 919 bytes .../__pycache__/monkey.cpython-310.pyc | Bin 0 -> 4647 bytes .../__pycache__/msvc.cpython-310.pyc | Bin 0 -> 42651 bytes .../__pycache__/namespaces.cpython-310.pyc | Bin 0 -> 3630 bytes .../__pycache__/package_index.cpython-310.pyc | Bin 0 -> 32504 bytes .../__pycache__/py34compat.cpython-310.pyc | Bin 0 -> 494 bytes .../__pycache__/sandbox.cpython-310.pyc | Bin 0 -> 15770 bytes .../__pycache__/unicode_utils.cpython-310.pyc | Bin 0 -> 1124 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 336 bytes .../__pycache__/wheel.cpython-310.pyc | Bin 0 -> 7362 bytes .../windows_support.cpython-310.pyc | Bin 0 -> 1037 bytes .../setuptools/_deprecation_warning.py | 7 + .../setuptools/_distutils/__init__.py | 15 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 468 bytes .../__pycache__/_msvccompiler.cpython-310.pyc | Bin 0 -> 13847 bytes .../__pycache__/archive_util.cpython-310.pyc | Bin 0 -> 6575 bytes .../__pycache__/bcppcompiler.cpython-310.pyc | Bin 0 -> 6562 bytes .../__pycache__/ccompiler.cpython-310.pyc | Bin 0 -> 33289 bytes .../__pycache__/cmd.cpython-310.pyc | Bin 0 -> 13962 bytes .../__pycache__/config.cpython-310.pyc | Bin 0 -> 3603 bytes .../__pycache__/core.cpython-310.pyc | Bin 0 -> 6670 bytes .../cygwinccompiler.cpython-310.pyc | Bin 0 -> 8756 bytes .../__pycache__/debug.cpython-310.pyc | Bin 0 -> 264 bytes .../__pycache__/dep_util.cpython-310.pyc | Bin 0 -> 2785 bytes .../__pycache__/dir_util.cpython-310.pyc | Bin 0 -> 5896 bytes .../__pycache__/dist.cpython-310.pyc | Bin 0 -> 34065 bytes .../__pycache__/errors.cpython-310.pyc | Bin 0 -> 5006 bytes .../__pycache__/extension.cpython-310.pyc | Bin 0 -> 7020 bytes .../__pycache__/fancy_getopt.cpython-310.pyc | Bin 0 -> 10646 bytes .../__pycache__/file_util.cpython-310.pyc | Bin 0 -> 5990 bytes .../__pycache__/filelist.cpython-310.pyc | Bin 0 -> 10836 bytes .../__pycache__/log.cpython-310.pyc | Bin 0 -> 2321 bytes .../__pycache__/msvc9compiler.cpython-310.pyc | Bin 0 -> 17576 bytes .../__pycache__/msvccompiler.cpython-310.pyc | Bin 0 -> 14795 bytes .../__pycache__/py35compat.cpython-310.pyc | Bin 0 -> 640 bytes .../__pycache__/py38compat.cpython-310.pyc | Bin 0 -> 437 bytes .../__pycache__/spawn.cpython-310.pyc | Bin 0 -> 2907 bytes .../__pycache__/sysconfig.cpython-310.pyc | Bin 0 -> 12574 bytes .../__pycache__/text_file.cpython-310.pyc | Bin 0 -> 8483 bytes .../__pycache__/unixccompiler.cpython-310.pyc | Bin 0 -> 6841 bytes .../__pycache__/util.cpython-310.pyc | Bin 0 -> 14227 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 7371 bytes .../versionpredicate.cpython-310.pyc | Bin 0 -> 5201 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 -> 543 bytes .../command/__pycache__/bdist.cpython-310.pyc | Bin 0 -> 3677 bytes .../__pycache__/bdist_dumb.cpython-310.pyc | Bin 0 -> 3658 bytes .../__pycache__/bdist_msi.cpython-310.pyc | Bin 0 -> 19734 bytes .../__pycache__/bdist_rpm.cpython-310.pyc | Bin 0 -> 12302 bytes .../__pycache__/bdist_wininst.cpython-310.pyc | Bin 0 -> 8643 bytes .../command/__pycache__/build.cpython-310.pyc | Bin 0 -> 3905 bytes .../__pycache__/build_clib.cpython-310.pyc | Bin 0 -> 4882 bytes .../__pycache__/build_ext.cpython-310.pyc | Bin 0 -> 16279 bytes .../__pycache__/build_py.cpython-310.pyc | Bin 0 -> 9901 bytes .../__pycache__/build_scripts.cpython-310.pyc | Bin 0 -> 4024 bytes .../command/__pycache__/check.cpython-310.pyc | Bin 0 -> 5021 bytes .../command/__pycache__/clean.cpython-310.pyc | Bin 0 -> 2160 bytes .../__pycache__/config.cpython-310.pyc | Bin 0 -> 10342 bytes .../__pycache__/install.cpython-310.pyc | Bin 0 -> 13876 bytes .../__pycache__/install_data.cpython-310.pyc | Bin 0 -> 2359 bytes .../install_egg_info.cpython-310.pyc | Bin 0 -> 3100 bytes .../install_headers.cpython-310.pyc | Bin 0 -> 1782 bytes .../__pycache__/install_lib.cpython-310.pyc | Bin 0 -> 5184 bytes .../install_scripts.cpython-310.pyc | Bin 0 -> 2211 bytes .../__pycache__/py37compat.cpython-310.pyc | Bin 0 -> 1056 bytes .../__pycache__/register.cpython-310.pyc | Bin 0 -> 8695 bytes .../command/__pycache__/sdist.cpython-310.pyc | Bin 0 -> 14511 bytes .../__pycache__/upload.cpython-310.pyc | Bin 0 -> 5387 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 | 392 + .../_distutils/command/build_scripts.py | 152 + .../setuptools/_distutils/command/check.py | 148 + .../setuptools/_distutils/command/clean.py | 76 + .../setuptools/_distutils/command/config.py | 344 + .../setuptools/_distutils/command/install.py | 678 ++ .../_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 | 578 ++ .../setuptools/_distutils/text_file.py | 286 + .../setuptools/_distutils/unixccompiler.py | 332 + .../setuptools/_distutils/util.py | 535 ++ .../setuptools/_distutils/version.py | 347 + .../setuptools/_distutils/versionpredicate.py | 166 + .../site-packages/setuptools/_imp.py | 82 + .../setuptools/_vendor/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 198 bytes .../__pycache__/ordered_set.cpython-310.pyc | Bin 0 -> 16334 bytes .../__pycache__/pyparsing.cpython-310.pyc | Bin 0 -> 198832 bytes .../_vendor/more_itertools/__init__.py | 4 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 279 bytes .../__pycache__/more.cpython-310.pyc | Bin 0 -> 110009 bytes .../__pycache__/recipes.cpython-310.pyc | Bin 0 -> 17979 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 -> 714 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 560 bytes .../__pycache__/_compat.cpython-310.pyc | Bin 0 -> 1160 bytes .../__pycache__/_structures.cpython-310.pyc | Bin 0 -> 2704 bytes .../__pycache__/_typing.cpython-310.pyc | Bin 0 -> 1516 bytes .../__pycache__/markers.cpython-310.pyc | Bin 0 -> 9198 bytes .../__pycache__/requirements.cpython-310.pyc | Bin 0 -> 4103 bytes .../__pycache__/specifiers.cpython-310.pyc | Bin 0 -> 20467 bytes .../__pycache__/tags.cpython-310.pyc | Bin 0 -> 17346 bytes .../__pycache__/utils.cpython-310.pyc | Bin 0 -> 1651 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 13031 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 + .../site-packages/setuptools/cli-32.exe | Bin 0 -> 65536 bytes .../site-packages/setuptools/cli-64.exe | Bin 0 -> 74752 bytes .../site-packages/setuptools/cli.exe | Bin 0 -> 65536 bytes .../setuptools/command/__init__.py | 8 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 387 bytes .../command/__pycache__/alias.cpython-310.pyc | Bin 0 -> 2389 bytes .../__pycache__/bdist_egg.cpython-310.pyc | Bin 0 -> 13115 bytes .../__pycache__/bdist_rpm.cpython-310.pyc | Bin 0 -> 1602 bytes .../__pycache__/build_clib.cpython-310.pyc | Bin 0 -> 2478 bytes .../__pycache__/build_ext.cpython-310.pyc | Bin 0 -> 9905 bytes .../__pycache__/build_py.cpython-310.pyc | Bin 0 -> 7882 bytes .../__pycache__/develop.cpython-310.pyc | Bin 0 -> 6165 bytes .../__pycache__/dist_info.cpython-310.pyc | Bin 0 -> 1407 bytes .../__pycache__/easy_install.cpython-310.pyc | Bin 0 -> 63739 bytes .../__pycache__/egg_info.cpython-310.pyc | Bin 0 -> 22033 bytes .../__pycache__/install.cpython-310.pyc | Bin 0 -> 4064 bytes .../install_egg_info.cpython-310.pyc | Bin 0 -> 2441 bytes .../__pycache__/install_lib.cpython-310.pyc | Bin 0 -> 4184 bytes .../install_scripts.cpython-310.pyc | Bin 0 -> 2442 bytes .../__pycache__/py36compat.cpython-310.pyc | Bin 0 -> 4549 bytes .../__pycache__/register.cpython-310.pyc | Bin 0 -> 853 bytes .../__pycache__/rotate.cpython-310.pyc | Bin 0 -> 2520 bytes .../__pycache__/saveopts.cpython-310.pyc | Bin 0 -> 939 bytes .../command/__pycache__/sdist.cpython-310.pyc | Bin 0 -> 6540 bytes .../__pycache__/setopt.cpython-310.pyc | Bin 0 -> 4701 bytes .../command/__pycache__/test.cpython-310.pyc | Bin 0 -> 8145 bytes .../__pycache__/upload.cpython-310.pyc | Bin 0 -> 826 bytes .../__pycache__/upload_docs.cpython-310.pyc | Bin 0 -> 6195 bytes .../site-packages/setuptools/command/alias.py | 78 + .../setuptools/command/bdist_egg.py | 456 + .../setuptools/command/bdist_rpm.py | 40 + .../setuptools/command/build_clib.py | 101 + .../setuptools/command/build_ext.py | 328 + .../setuptools/command/build_py.py | 232 + .../setuptools/command/develop.py | 193 + .../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 | 149 + .../site-packages/setuptools/command/test.py | 252 + .../setuptools/command/upload.py | 17 + .../setuptools/command/upload_docs.py | 202 + .../site-packages/setuptools/config.py | 749 ++ .../site-packages/setuptools/dep_util.py | 25 + .../site-packages/setuptools/depends.py | 175 + .../site-packages/setuptools/dist.py | 1150 +++ .../site-packages/setuptools/errors.py | 16 + .../site-packages/setuptools/extension.py | 55 + .../setuptools/extern/__init__.py | 73 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 2948 bytes .../site-packages/setuptools/glob.py | 167 + .../site-packages/setuptools/gui-32.exe | Bin 0 -> 65536 bytes .../site-packages/setuptools/gui-64.exe | Bin 0 -> 75264 bytes .../site-packages/setuptools/gui.exe | Bin 0 -> 65536 bytes .../site-packages/setuptools/installer.py | 97 + .../site-packages/setuptools/launch.py | 36 + .../site-packages/setuptools/monkey.py | 177 + .../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 + .../site-packages/setuptools/sandbox.py | 530 ++ .../setuptools/script (dev).tmpl | 6 + .../site-packages/setuptools/script.tmpl | 3 + .../site-packages/setuptools/unicode_utils.py | 42 + .../site-packages/setuptools/version.py | 6 + .../site-packages/setuptools/wheel.py | 213 + .../setuptools/windows_support.py | 29 + .../site-packages/werkzeug/__init__.py | 6 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 362 bytes .../__pycache__/_internal.cpython-310.pyc | Bin 0 -> 18616 bytes .../__pycache__/_reloader.cpython-310.pyc | Bin 0 -> 12088 bytes .../datastructures.cpython-310.pyc | Bin 0 -> 104996 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 29844 bytes .../__pycache__/filesystem.cpython-310.pyc | Bin 0 -> 2090 bytes .../__pycache__/formparser.cpython-310.pyc | Bin 0 -> 14306 bytes .../werkzeug/__pycache__/http.cpython-310.pyc | Bin 0 -> 38667 bytes .../__pycache__/local.cpython-310.pyc | Bin 0 -> 22818 bytes .../__pycache__/routing.cpython-310.pyc | Bin 0 -> 73474 bytes .../__pycache__/security.cpython-310.pyc | Bin 0 -> 8229 bytes .../__pycache__/serving.cpython-310.pyc | Bin 0 -> 31162 bytes .../werkzeug/__pycache__/test.cpython-310.pyc | Bin 0 -> 39245 bytes .../__pycache__/testapp.cpython-310.pyc | Bin 0 -> 9636 bytes .../werkzeug/__pycache__/urls.cpython-310.pyc | Bin 0 -> 36543 bytes .../__pycache__/user_agent.cpython-310.pyc | Bin 0 -> 1848 bytes .../__pycache__/useragents.cpython-310.pyc | Bin 0 -> 6885 bytes .../__pycache__/utils.cpython-310.pyc | Bin 0 -> 33005 bytes .../werkzeug/__pycache__/wsgi.cpython-310.pyc | Bin 0 -> 30408 bytes .../site-packages/werkzeug/_internal.py | 626 ++ .../site-packages/werkzeug/_reloader.py | 430 + .../site-packages/werkzeug/datastructures.py | 3059 ++++++ .../site-packages/werkzeug/datastructures.pyi | 912 ++ .../site-packages/werkzeug/debug/__init__.py | 500 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 13127 bytes .../debug/__pycache__/console.cpython-310.pyc | Bin 0 -> 7926 bytes .../debug/__pycache__/repr.cpython-310.pyc | Bin 0 -> 8891 bytes .../debug/__pycache__/tbtools.cpython-310.pyc | Bin 0 -> 18179 bytes .../site-packages/werkzeug/debug/console.py | 214 + .../site-packages/werkzeug/debug/repr.py | 284 + .../werkzeug/debug/shared/FONT_LICENSE | 96 + .../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/source.png | Bin 0 -> 818 bytes .../werkzeug/debug/shared/style.css | 163 + .../werkzeug/debug/shared/ubuntu.ttf | Bin 0 -> 70220 bytes .../site-packages/werkzeug/debug/tbtools.py | 600 ++ .../site-packages/werkzeug/exceptions.py | 944 ++ .../site-packages/werkzeug/filesystem.py | 55 + .../site-packages/werkzeug/formparser.py | 495 + .../python3.10/site-packages/werkzeug/http.py | 1393 +++ .../site-packages/werkzeug/local.py | 690 ++ .../werkzeug/middleware/__init__.py | 22 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 707 bytes .../__pycache__/dispatcher.cpython-310.pyc | Bin 0 -> 2791 bytes .../__pycache__/http_proxy.cpython-310.pyc | Bin 0 -> 6881 bytes .../__pycache__/lint.cpython-310.pyc | Bin 0 -> 12748 bytes .../__pycache__/profiler.cpython-310.pyc | Bin 0 -> 4998 bytes .../__pycache__/proxy_fix.cpython-310.pyc | Bin 0 -> 6209 bytes .../__pycache__/shared_data.cpython-310.pyc | Bin 0 -> 9925 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 | 320 + .../site-packages/werkzeug/py.typed | 0 .../site-packages/werkzeug/routing.py | 2342 +++++ .../site-packages/werkzeug/sansio/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 195 bytes .../__pycache__/multipart.cpython-310.pyc | Bin 0 -> 6469 bytes .../__pycache__/request.cpython-310.pyc | Bin 0 -> 17119 bytes .../__pycache__/response.cpython-310.pyc | Bin 0 -> 22399 bytes .../sansio/__pycache__/utils.cpython-310.pyc | Bin 0 -> 3934 bytes .../werkzeug/sansio/multipart.py | 260 + .../site-packages/werkzeug/sansio/request.py | 548 ++ .../site-packages/werkzeug/sansio/response.py | 704 ++ .../site-packages/werkzeug/sansio/utils.py | 142 + .../site-packages/werkzeug/security.py | 247 + .../site-packages/werkzeug/serving.py | 1088 +++ .../python3.10/site-packages/werkzeug/test.py | 1331 +++ .../site-packages/werkzeug/testapp.py | 240 + .../python3.10/site-packages/werkzeug/urls.py | 1211 +++ .../site-packages/werkzeug/user_agent.py | 47 + .../site-packages/werkzeug/useragents.py | 215 + .../site-packages/werkzeug/utils.py | 1099 +++ .../werkzeug/wrappers/__init__.py | 16 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 918 bytes .../__pycache__/accept.cpython-310.pyc | Bin 0 -> 828 bytes .../wrappers/__pycache__/auth.cpython-310.pyc | Bin 0 -> 1222 bytes .../__pycache__/base_request.cpython-310.pyc | Bin 0 -> 1740 bytes .../__pycache__/base_response.cpython-310.pyc | Bin 0 -> 1751 bytes .../common_descriptors.cpython-310.pyc | Bin 0 -> 1299 bytes .../wrappers/__pycache__/cors.cpython-310.pyc | Bin 0 -> 1207 bytes .../wrappers/__pycache__/etag.cpython-310.pyc | Bin 0 -> 1207 bytes .../wrappers/__pycache__/json.cpython-310.pyc | Bin 0 -> 820 bytes .../__pycache__/request.cpython-310.pyc | Bin 0 -> 21400 bytes .../__pycache__/response.cpython-310.pyc | Bin 0 -> 29815 bytes .../__pycache__/user_agent.cpython-310.pyc | Bin 0 -> 841 bytes .../site-packages/werkzeug/wrappers/accept.py | 14 + .../site-packages/werkzeug/wrappers/auth.py | 26 + .../werkzeug/wrappers/base_request.py | 36 + .../werkzeug/wrappers/base_response.py | 36 + .../werkzeug/wrappers/common_descriptors.py | 26 + .../site-packages/werkzeug/wrappers/cors.py | 26 + .../site-packages/werkzeug/wrappers/etag.py | 26 + .../site-packages/werkzeug/wrappers/json.py | 13 + .../werkzeug/wrappers/request.py | 660 ++ .../werkzeug/wrappers/response.py | 891 ++ .../werkzeug/wrappers/user_agent.py | 14 + .../python3.10/site-packages/werkzeug/wsgi.py | 982 ++ src/myvenv/lib64 | 1 + src/myvenv/pyvenv.cfg | 3 + src/requirements.txt | 3 + src/static/styles/0-dracula.css | 243 + src/static/styles/1-light.css | 245 + src/static/styles/WorkSans-Bold.ttf | Bin 0 -> 192548 bytes src/static/styles/WorkSans-BoldItalic.ttf | Bin 0 -> 176364 bytes src/static/styles/WorkSans-Italic.ttf | Bin 0 -> 175724 bytes src/static/styles/WorkSans-Regular.ttf | Bin 0 -> 192140 bytes src/templates/edit.html | 37 + src/templates/export.html | 17 + src/templates/homepage.html | 38 + src/templates/read.html | 20 + ssdark.png | Bin 0 -> 17449 bytes sslight.png | Bin 0 -> 16271 bytes 1421 files changed, 270965 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 data/notes.pickle create mode 100644 docker-compose.yml create mode 100644 squipnotes.png create mode 100755 src/app.py create mode 100644 src/classes.py create mode 100644 src/funcs.py create mode 100644 src/myvenv/bin/Activate.ps1 create mode 100644 src/myvenv/bin/activate create mode 100644 src/myvenv/bin/activate.csh create mode 100644 src/myvenv/bin/activate.fish create mode 100755 src/myvenv/bin/flask create mode 100755 src/myvenv/bin/pip create mode 100755 src/myvenv/bin/pip3 create mode 100755 src/myvenv/bin/pip3.10 create mode 120000 src/myvenv/bin/python create mode 120000 src/myvenv/bin/python3 create mode 120000 src/myvenv/bin/python3.10 create mode 100644 src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/INSTALLER create mode 100644 src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/LICENSE.rst create mode 100644 src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/METADATA create mode 100644 src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/RECORD create mode 100644 src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/REQUESTED create mode 100644 src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/WHEEL create mode 100644 src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/entry_points.txt create mode 100644 src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/top_level.txt create mode 100644 src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/INSTALLER create mode 100644 src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/LICENSE.rst create mode 100644 src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/METADATA create mode 100644 src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/RECORD create mode 100644 src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/WHEEL create mode 100644 src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/entry_points.txt create mode 100644 src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/top_level.txt create mode 100644 src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/INSTALLER create mode 100644 src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/LICENSE.rst create mode 100644 src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/METADATA create mode 100644 src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/RECORD create mode 100644 src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/WHEEL create mode 100644 src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/top_level.txt create mode 100644 src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/INSTALLER create mode 100644 src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/LICENSE.rst create mode 100644 src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/METADATA create mode 100644 src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/RECORD create mode 100644 src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/WHEEL create mode 100644 src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/top_level.txt create mode 100644 src/myvenv/lib/python3.10/site-packages/_distutils_hack/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/_distutils_hack/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/_distutils_hack/__pycache__/override.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/_distutils_hack/override.py create mode 100644 src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/INSTALLER create mode 100644 src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/LICENSE.rst create mode 100644 src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/METADATA create mode 100644 src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/RECORD create mode 100644 src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/WHEEL create mode 100644 src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/top_level.txt create mode 100644 src/myvenv/lib/python3.10/site-packages/click/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/click/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/click/__pycache__/_compat.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/click/__pycache__/_termui_impl.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/click/__pycache__/_textwrap.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/click/__pycache__/_unicodefun.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/click/__pycache__/_winconsole.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/click/__pycache__/core.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/click/__pycache__/decorators.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/click/__pycache__/exceptions.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/click/__pycache__/formatting.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/click/__pycache__/globals.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/click/__pycache__/parser.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/click/__pycache__/shell_completion.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/click/__pycache__/termui.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/click/__pycache__/testing.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/click/__pycache__/types.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/click/__pycache__/utils.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/click/_compat.py create mode 100644 src/myvenv/lib/python3.10/site-packages/click/_termui_impl.py create mode 100644 src/myvenv/lib/python3.10/site-packages/click/_textwrap.py create mode 100644 src/myvenv/lib/python3.10/site-packages/click/_unicodefun.py create mode 100644 src/myvenv/lib/python3.10/site-packages/click/_winconsole.py create mode 100644 src/myvenv/lib/python3.10/site-packages/click/core.py create mode 100644 src/myvenv/lib/python3.10/site-packages/click/decorators.py create mode 100644 src/myvenv/lib/python3.10/site-packages/click/exceptions.py create mode 100644 src/myvenv/lib/python3.10/site-packages/click/formatting.py create mode 100644 src/myvenv/lib/python3.10/site-packages/click/globals.py create mode 100644 src/myvenv/lib/python3.10/site-packages/click/parser.py create mode 100644 src/myvenv/lib/python3.10/site-packages/click/py.typed create mode 100644 src/myvenv/lib/python3.10/site-packages/click/shell_completion.py create mode 100644 src/myvenv/lib/python3.10/site-packages/click/termui.py create mode 100644 src/myvenv/lib/python3.10/site-packages/click/testing.py create mode 100644 src/myvenv/lib/python3.10/site-packages/click/types.py create mode 100644 src/myvenv/lib/python3.10/site-packages/click/utils.py create mode 100644 src/myvenv/lib/python3.10/site-packages/distutils-precedence.pth create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__main__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/__main__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/app.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/blueprints.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/cli.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/config.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/ctx.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/debughelpers.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/globals.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/helpers.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/logging.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/scaffold.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/sessions.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/signals.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/templating.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/testing.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/typing.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/views.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/__pycache__/wrappers.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/app.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/blueprints.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/cli.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/config.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/ctx.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/debughelpers.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/globals.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/helpers.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/json/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/json/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/json/__pycache__/tag.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/json/tag.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/logging.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/py.typed create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/scaffold.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/sessions.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/signals.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/templating.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/testing.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/typing.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/views.py create mode 100644 src/myvenv/lib/python3.10/site-packages/flask/wrappers.py create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous-2.1.1.dist-info/INSTALLER create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous-2.1.1.dist-info/LICENSE.rst create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous-2.1.1.dist-info/METADATA create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous-2.1.1.dist-info/RECORD create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous-2.1.1.dist-info/WHEEL create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous-2.1.1.dist-info/top_level.txt create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous/__pycache__/_json.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous/__pycache__/encoding.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous/__pycache__/exc.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous/__pycache__/serializer.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous/__pycache__/signer.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous/__pycache__/timed.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous/__pycache__/url_safe.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous/_json.py create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous/encoding.py create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous/exc.py create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous/py.typed create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous/serializer.py create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous/signer.py create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous/timed.py create mode 100644 src/myvenv/lib/python3.10/site-packages/itsdangerous/url_safe.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/_identifier.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/async_utils.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/bccache.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/compiler.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/constants.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/debug.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/defaults.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/environment.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/exceptions.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/ext.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/filters.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/idtracking.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/lexer.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/loaders.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/meta.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/nativetypes.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/nodes.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/optimizer.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/parser.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/runtime.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/sandbox.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/tests.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/utils.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/__pycache__/visitor.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/_identifier.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/async_utils.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/bccache.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/compiler.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/constants.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/debug.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/defaults.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/environment.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/exceptions.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/ext.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/filters.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/idtracking.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/lexer.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/loaders.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/meta.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/nativetypes.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/nodes.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/optimizer.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/parser.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/py.typed create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/runtime.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/sandbox.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/tests.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/utils.py create mode 100644 src/myvenv/lib/python3.10/site-packages/jinja2/visitor.py create mode 100644 src/myvenv/lib/python3.10/site-packages/markupsafe/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/markupsafe/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/markupsafe/__pycache__/_native.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/markupsafe/_native.py create mode 100644 src/myvenv/lib/python3.10/site-packages/markupsafe/_speedups.c create mode 100755 src/myvenv/lib/python3.10/site-packages/markupsafe/_speedups.cpython-310-x86_64-linux-gnu.so create mode 100644 src/myvenv/lib/python3.10/site-packages/markupsafe/_speedups.pyi create mode 100644 src/myvenv/lib/python3.10/site-packages/markupsafe/py.typed create mode 100644 src/myvenv/lib/python3.10/site-packages/pip-21.2.4.dist-info/INSTALLER create mode 100644 src/myvenv/lib/python3.10/site-packages/pip-21.2.4.dist-info/LICENSE.txt create mode 100644 src/myvenv/lib/python3.10/site-packages/pip-21.2.4.dist-info/METADATA create mode 100644 src/myvenv/lib/python3.10/site-packages/pip-21.2.4.dist-info/RECORD create mode 100644 src/myvenv/lib/python3.10/site-packages/pip-21.2.4.dist-info/REQUESTED create mode 100644 src/myvenv/lib/python3.10/site-packages/pip-21.2.4.dist-info/WHEEL create mode 100644 src/myvenv/lib/python3.10/site-packages/pip-21.2.4.dist-info/entry_points.txt create mode 100644 src/myvenv/lib/python3.10/site-packages/pip-21.2.4.dist-info/top_level.txt create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/__main__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/__pycache__/__main__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/__pycache__/build_env.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/__pycache__/cache.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/__pycache__/configuration.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/__pycache__/exceptions.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/__pycache__/main.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/__pycache__/pyproject.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/build_env.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cache.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/main.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/parser.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/progress_bars.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/autocompletion.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/base_command.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/cmdoptions.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/command_context.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/main.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/main_parser.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/parser.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/progress_bars.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/req_command.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/spinners.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/cli/status_codes.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/cache.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/check.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/completion.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/debug.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/download.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/hash.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/help.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/index.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/install.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/list.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/search.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/show.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/cache.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/check.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/completion.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/configuration.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/debug.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/download.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/freeze.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/hash.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/help.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/index.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/install.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/list.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/search.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/show.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/uninstall.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/commands/wheel.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/configuration.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/distributions/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/distributions/__pycache__/base.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/distributions/base.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/distributions/installed.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/distributions/sdist.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/distributions/wheel.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/exceptions.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/index/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/index/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/index/__pycache__/collector.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/index/__pycache__/package_finder.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/index/__pycache__/sources.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/index/collector.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/index/package_finder.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/index/sources.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/locations/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/locations/__pycache__/base.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/locations/_distutils.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/locations/_sysconfig.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/locations/base.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/main.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/metadata/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/metadata/__pycache__/base.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/metadata/base.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/metadata/pkg_resources.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/candidate.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/format_control.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/index.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/link.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/scheme.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/target_python.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/wheel.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/candidate.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/direct_url.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/format_control.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/index.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/link.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/scheme.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/search_scope.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/selection_prefs.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/target_python.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/models/wheel.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/network/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/network/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/network/__pycache__/auth.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/network/__pycache__/cache.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/network/__pycache__/download.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/network/__pycache__/session.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/network/__pycache__/utils.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/network/auth.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/network/cache.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/network/download.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/network/lazy_wheel.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/network/session.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/network/utils.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/network/xmlrpc.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/__pycache__/check.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/build/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/build/metadata.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/build/metadata_legacy.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/build/wheel.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/build/wheel_legacy.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/check.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/freeze.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/install/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/install/__pycache__/legacy.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/install/editable_legacy.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/install/legacy.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/install/wheel.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/operations/prepare.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/pyproject.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/req/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/req/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/req/__pycache__/constructors.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/req/__pycache__/req_file.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/req/__pycache__/req_install.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/req/__pycache__/req_set.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/req/__pycache__/req_tracker.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/req/constructors.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/req/req_file.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/req/req_install.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/req/req_set.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/req/req_tracker.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/req/req_uninstall.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/__pycache__/base.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/base.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/legacy/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/legacy/resolver.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/base.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/candidates.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/factory.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/provider.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/reporter.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/requirements.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/resolver.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/self_outdated_check.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/_log.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/compat.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/distutils_args.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/inject_securetransport.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/logging.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/misc.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/models.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/parallel.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/pkg_resources.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/unpacking.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/urls.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/_log.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/appdirs.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/compat.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/compatibility_tags.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/datetime.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/deprecation.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/direct_url_helpers.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/distutils_args.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/encoding.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/entrypoints.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/filesystem.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/filetypes.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/glibc.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/hashes.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/inject_securetransport.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/logging.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/misc.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/models.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/packaging.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/parallel.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/pkg_resources.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/setuptools_build.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/subprocess.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/temp_dir.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/unpacking.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/urls.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/virtualenv.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/utils/wheel.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/vcs/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/vcs/__pycache__/git.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/vcs/bazaar.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/vcs/git.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/vcs/mercurial.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/vcs/subversion.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/vcs/versioncontrol.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_internal/wheel_builder.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/__pycache__/appdirs.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/__pycache__/distro.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/__pycache__/pyparsing.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/__pycache__/six.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/appdirs.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/compat.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/_cmd.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/adapter.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/cache.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/caches/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/compat.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/controller.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/filewrapper.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/heuristics.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/serialize.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/wrapper.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/certifi/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/certifi/__main__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/certifi/cacert.pem create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/certifi/core.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/big5freq.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/big5prober.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/chardistribution.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/charsetgroupprober.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/charsetprober.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/compat.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/cp949prober.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/enums.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/escprober.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/escsm.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/eucjpprober.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/euckrfreq.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/euckrprober.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/euctwfreq.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/euctwprober.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/gb2312freq.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/gb2312prober.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/hebrewprober.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/jisfreq.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/jpcntx.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/langgreekmodel.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/langhebrewmodel.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/langhungarianmodel.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/langrussianmodel.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/langthaimodel.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/langturkishmodel.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/latin1prober.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/mbcssm.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/sbcharsetprober.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/sbcsgroupprober.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/sjisprober.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/universaldetector.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/utf8prober.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/version.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/big5freq.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/big5prober.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/chardistribution.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/charsetgroupprober.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/charsetprober.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/cli/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/cli/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/cli/chardetect.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/codingstatemachine.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/compat.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/cp949prober.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/enums.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/escprober.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/escsm.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/eucjpprober.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/euckrfreq.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/euckrprober.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/euctwfreq.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/euctwprober.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/gb2312freq.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/gb2312prober.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/hebrewprober.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/jisfreq.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/jpcntx.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/langbulgarianmodel.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/langgreekmodel.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/langhebrewmodel.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/langhungarianmodel.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/langrussianmodel.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/langthaimodel.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/langturkishmodel.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/latin1prober.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/mbcharsetprober.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/mbcsgroupprober.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/mbcssm.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/metadata/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/metadata/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/metadata/__pycache__/languages.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/metadata/languages.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/sbcharsetprober.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/sbcsgroupprober.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/sjisprober.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/universaldetector.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/utf8prober.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/chardet/version.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/colorama/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/colorama/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/colorama/__pycache__/ansi.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/colorama/__pycache__/ansitowin32.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/colorama/__pycache__/initialise.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/colorama/__pycache__/win32.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/colorama/__pycache__/winterm.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/colorama/ansi.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/colorama/ansitowin32.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/colorama/initialise.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/colorama/win32.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/colorama/winterm.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/_backport/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/_backport/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/_backport/__pycache__/misc.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/_backport/__pycache__/shutil.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/_backport/__pycache__/sysconfig.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/_backport/__pycache__/tarfile.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/_backport/misc.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/_backport/shutil.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/_backport/sysconfig.cfg create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/_backport/sysconfig.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/_backport/tarfile.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/compat.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/database.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/index.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/locators.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/manifest.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/markers.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/metadata.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/resources.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/scripts.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/t32.exe create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/t64.exe create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/util.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/version.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/w32.exe create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/w64.exe create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distlib/wheel.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/distro.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/__pycache__/_ihatexml.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/__pycache__/_inputstream.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/__pycache__/_tokenizer.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/__pycache__/_utils.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/__pycache__/constants.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/__pycache__/html5parser.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/__pycache__/serializer.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/_ihatexml.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/_inputstream.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/_tokenizer.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/_trie/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/_trie/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/_trie/__pycache__/_base.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/_trie/__pycache__/py.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/_trie/_base.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/_trie/py.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/_utils.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/constants.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/__pycache__/alphabeticalattributes.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/__pycache__/base.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/__pycache__/inject_meta_charset.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/__pycache__/lint.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/__pycache__/optionaltags.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/__pycache__/sanitizer.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/__pycache__/whitespace.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/alphabeticalattributes.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/base.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/inject_meta_charset.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/lint.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/optionaltags.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/sanitizer.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/whitespace.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/html5parser.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/serializer.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treeadapters/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treeadapters/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treeadapters/__pycache__/genshi.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treeadapters/__pycache__/sax.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treeadapters/genshi.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treeadapters/sax.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treebuilders/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/base.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/dom.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/etree.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/etree_lxml.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treebuilders/base.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treebuilders/dom.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treebuilders/etree.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treebuilders/etree_lxml.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treewalkers/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/base.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/dom.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/etree.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/etree_lxml.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/genshi.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treewalkers/base.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treewalkers/dom.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treewalkers/etree.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treewalkers/etree_lxml.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/treewalkers/genshi.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/idna/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/idna/__pycache__/core.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/idna/codec.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/idna/compat.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/idna/core.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/idna/idnadata.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/idna/intranges.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/idna/package_data.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/idna/uts46data.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/msgpack/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/msgpack/__pycache__/_version.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/msgpack/_version.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/msgpack/exceptions.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/msgpack/ext.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/msgpack/fallback.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/__about__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/__about__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/_manylinux.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/_musllinux.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/_structures.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/markers.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/requirements.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/specifiers.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/tags.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/utils.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/packaging/version.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/__pycache__/build.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/__pycache__/check.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/__pycache__/colorlog.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/__pycache__/compat.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/__pycache__/dirtools.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/__pycache__/envbuild.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/__pycache__/meta.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/__pycache__/wrappers.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/build.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/check.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/colorlog.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/compat.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/dirtools.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/envbuild.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/in_process/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/in_process/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/in_process/__pycache__/_in_process.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/in_process/_in_process.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/meta.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pep517/wrappers.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pkg_resources/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pkg_resources/__pycache__/py31compat.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pkg_resources/py31compat.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/progress/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/progress/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/progress/__pycache__/bar.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/progress/__pycache__/counter.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/progress/__pycache__/spinner.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/progress/bar.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/progress/counter.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/progress/spinner.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/pyparsing.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/api.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/help.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/models.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/__version__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/_internal_utils.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/adapters.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/api.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/auth.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/certs.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/compat.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/cookies.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/exceptions.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/help.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/hooks.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/models.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/packages.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/sessions.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/status_codes.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/structures.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/requests/utils.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/resolvelib/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/resolvelib/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/resolvelib/__pycache__/providers.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/resolvelib/__pycache__/reporters.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/resolvelib/__pycache__/structs.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/resolvelib/compat/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/resolvelib/providers.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/resolvelib/reporters.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/resolvelib/resolvers.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/resolvelib/structs.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/six.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/_asyncio.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/_utils.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/after.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/before.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/before_sleep.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/nap.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/retry.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/stop.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/tornadoweb.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/wait.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/_asyncio.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/_utils.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/after.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/before.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/before_sleep.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/nap.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/retry.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/stop.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/tornadoweb.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tenacity/wait.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tomli/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tomli/_parser.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/tomli/_re.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/_collections.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/_version.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/connection.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/connectionpool.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/appengine.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/securetransport.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/socks.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/exceptions.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/fields.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/filepost.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/six.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__pycache__/_implementation.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/poolmanager.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/request.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/response.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/connection.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/proxy.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/queue.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/request.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/response.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/retry.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/ssl_.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/ssltransport.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/timeout.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/url.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/wait.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/vendor.txt create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/webencodings/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/webencodings/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/webencodings/__pycache__/labels.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/webencodings/__pycache__/mklabels.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/webencodings/__pycache__/tests.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/webencodings/labels.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/webencodings/mklabels.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/webencodings/tests.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/_vendor/webencodings/x_user_defined.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pip/py.typed create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/__pycache__/appdirs.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/__pycache__/pyparsing.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/appdirs.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__about__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/__about__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/_compat.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/_structures.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/_typing.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/markers.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/requirements.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/specifiers.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/tags.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/utils.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/version.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_compat.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_structures.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_typing.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/markers.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/requirements.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/specifiers.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/tags.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/utils.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/version.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/extern/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/extern/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/tests/data/my-test-package-source/__pycache__/setup.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/pkg_resources/tests/data/my-test-package-source/setup.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools-58.1.0.dist-info/INSTALLER create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools-58.1.0.dist-info/LICENSE create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools-58.1.0.dist-info/METADATA create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools-58.1.0.dist-info/RECORD create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools-58.1.0.dist-info/REQUESTED create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools-58.1.0.dist-info/WHEEL create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools-58.1.0.dist-info/entry_points.txt create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools-58.1.0.dist-info/top_level.txt create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/_deprecation_warning.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/_imp.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/archive_util.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/build_meta.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/config.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/dep_util.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/depends.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/dist.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/errors.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/extension.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/glob.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/installer.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/launch.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/monkey.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/msvc.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/namespaces.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/package_index.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/py34compat.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/sandbox.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/unicode_utils.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/version.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/wheel.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/__pycache__/windows_support.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_deprecation_warning.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/_msvccompiler.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/archive_util.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/bcppcompiler.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/ccompiler.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/cmd.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/config.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/core.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/cygwinccompiler.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/debug.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/dep_util.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/dir_util.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/dist.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/errors.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/extension.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/fancy_getopt.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/file_util.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/filelist.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/log.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/msvc9compiler.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/msvccompiler.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/py35compat.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/py38compat.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/spawn.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/sysconfig.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/text_file.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/unixccompiler.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/util.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/version.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/versionpredicate.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/_msvccompiler.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/archive_util.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/bcppcompiler.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/ccompiler.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/cmd.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/bdist.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/bdist_dumb.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/bdist_msi.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/bdist_rpm.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/bdist_wininst.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/build.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/build_clib.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/build_ext.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/build_py.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/build_scripts.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/check.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/clean.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/config.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/install.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/install_data.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/install_egg_info.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/install_headers.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/install_lib.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/install_scripts.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/py37compat.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/register.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/sdist.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/upload.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/bdist.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/bdist_dumb.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/bdist_msi.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/bdist_rpm.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/bdist_wininst.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/build.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/build_clib.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/build_ext.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/build_py.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/build_scripts.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/check.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/clean.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/config.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/install.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/install_data.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/install_egg_info.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/install_headers.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/install_lib.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/install_scripts.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/py37compat.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/register.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/sdist.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/command/upload.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/config.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/core.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/cygwinccompiler.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/debug.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/dep_util.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/dir_util.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/dist.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/errors.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/extension.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/fancy_getopt.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/file_util.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/filelist.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/log.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/msvc9compiler.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/msvccompiler.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/py35compat.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/py38compat.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/spawn.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/sysconfig.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/text_file.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/unixccompiler.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/util.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/version.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_distutils/versionpredicate.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_imp.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/__pycache__/ordered_set.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/__pycache__/pyparsing.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/__pycache__/more.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/__pycache__/recipes.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/more.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/recipes.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/ordered_set.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__about__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/__about__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/_compat.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/_structures.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/_typing.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/markers.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/requirements.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/specifiers.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/tags.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/utils.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/version.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/_compat.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/_structures.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/_typing.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/markers.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/requirements.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/specifiers.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/tags.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/utils.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/packaging/version.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/archive_util.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/build_meta.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/cli-32.exe create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/cli-64.exe create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/cli.exe create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/alias.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/bdist_egg.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/bdist_rpm.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/build_clib.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/build_ext.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/build_py.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/develop.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/dist_info.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/easy_install.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/egg_info.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/install.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/install_egg_info.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/install_lib.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/install_scripts.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/py36compat.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/register.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/rotate.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/saveopts.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/sdist.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/setopt.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/test.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/upload.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/__pycache__/upload_docs.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/alias.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/bdist_egg.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/bdist_rpm.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/build_clib.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/build_ext.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/build_py.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/develop.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/dist_info.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/easy_install.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/egg_info.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/install.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/install_egg_info.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/install_lib.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/install_scripts.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/launcher manifest.xml create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/py36compat.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/register.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/rotate.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/saveopts.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/sdist.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/setopt.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/test.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/upload.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/command/upload_docs.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/config.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/dep_util.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/depends.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/dist.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/errors.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/extension.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/extern/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/extern/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/glob.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/gui-32.exe create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/gui-64.exe create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/gui.exe create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/installer.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/launch.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/monkey.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/msvc.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/namespaces.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/package_index.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/py34compat.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/sandbox.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/script (dev).tmpl create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/script.tmpl create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/unicode_utils.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/version.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/wheel.py create mode 100644 src/myvenv/lib/python3.10/site-packages/setuptools/windows_support.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/_internal.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/_reloader.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/datastructures.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/exceptions.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/filesystem.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/formparser.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/http.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/local.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/routing.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/security.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/serving.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/test.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/testapp.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/urls.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/user_agent.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/useragents.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/utils.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/__pycache__/wsgi.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/_internal.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/_reloader.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/datastructures.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/datastructures.pyi create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/debug/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/debug/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/debug/__pycache__/console.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/debug/__pycache__/repr.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/debug/__pycache__/tbtools.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/debug/console.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/debug/repr.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/debug/shared/FONT_LICENSE create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/debug/shared/ICON_LICENSE.md create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/debug/shared/console.png create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/debug/shared/debugger.js create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/debug/shared/less.png create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/debug/shared/more.png create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/debug/shared/source.png create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/debug/shared/style.css create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/debug/shared/ubuntu.ttf create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/debug/tbtools.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/exceptions.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/filesystem.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/formparser.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/http.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/local.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/dispatcher.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/http_proxy.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/lint.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/profiler.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/proxy_fix.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/shared_data.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/dispatcher.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/http_proxy.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/lint.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/profiler.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/proxy_fix.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/shared_data.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/py.typed create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/routing.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/__pycache__/multipart.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/__pycache__/request.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/__pycache__/response.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/__pycache__/utils.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/multipart.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/request.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/response.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/utils.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/security.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/serving.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/test.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/testapp.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/urls.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/user_agent.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/useragents.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/utils.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__init__.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/__init__.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/accept.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/auth.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/base_request.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/base_response.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/common_descriptors.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/cors.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/etag.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/json.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/request.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/response.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/user_agent.cpython-310.pyc create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/accept.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/auth.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/base_request.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/base_response.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/common_descriptors.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/cors.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/etag.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/json.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/request.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/response.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/user_agent.py create mode 100644 src/myvenv/lib/python3.10/site-packages/werkzeug/wsgi.py create mode 120000 src/myvenv/lib64 create mode 100644 src/myvenv/pyvenv.cfg create mode 100644 src/requirements.txt create mode 100644 src/static/styles/0-dracula.css create mode 100644 src/static/styles/1-light.css create mode 100644 src/static/styles/WorkSans-Bold.ttf create mode 100644 src/static/styles/WorkSans-BoldItalic.ttf create mode 100644 src/static/styles/WorkSans-Italic.ttf create mode 100644 src/static/styles/WorkSans-Regular.ttf create mode 100644 src/templates/edit.html create mode 100644 src/templates/export.html create mode 100644 src/templates/homepage.html create mode 100644 src/templates/read.html create mode 100644 ssdark.png create mode 100644 sslight.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..696e65e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +./data +src/data +src/__pycache__ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4f211c7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3-slim-bullseye +WORKDIR /app +COPY ./src/requirements.txt /app/requirements.txt +RUN pip install --no-cache-dir --upgrade pip +RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt +VOLUME ["/app/data"] +COPY ./src /app +EXPOSE 8080 +ENV FLASK_APP=app +CMD [ "python", "-m" , "flask", "run", "--host=0.0.0.0", "--port=8080" ] diff --git a/README.md b/README.md new file mode 100644 index 0000000..84cb8c3 --- /dev/null +++ b/README.md @@ -0,0 +1,52 @@ +# squip_notes + +This is a basic notes-taking program. It uses python with flask and pickle, to give a really light and simple web interface for note taking. + +It uses the [dracula](https://github.com/dracula/dracula-theme) colors. +![dark theme screenshot](./ssdark.png) +![light theme screenshot](./sslight.png) +![Screenshot of the application](./squipnotes.png) + +# Features +* No accounts : this is made to be used as a single page (you can't have multiple user accounts). This is best suited as a personnal, self-hosted application in your own network (or it could also work for a work team). +* Simplicity: Simply get on the page and start writing. The notes syntax is markdown. +* Themes : As for now, there is a default dark theme (dracula), and an optionnal light theme (loosely based on solarized light). They can be selected via the interface. + +# Themes (adding your own) +All themes are in src/static/styles. They are the .css files. If you want to add your own, simply copy one of the existing files to a new one, named after the others. The numbers in the css file names determine the priority (make yours priority 0 to have it be the default). + +## Changing the code syntax highlight theme +* Install pygmentyze (it then must be in your path; pip generally installs things in ~/.local/bin when using a Linux OS): +``` +python3 pip install pygmentize +``` +* List available themes in a python shell: +```python +from pygments.styles import STYLE_MAP +print(STYLE_MAP.keys()) +``` +* Choose one, dracula for example +* Generate the CSS from your bash/zsh/cmd... shell in a styles.css file: +```bash +pygmentize -S dracula -f html -a .codehilite > styles.css +``` +* Replace all css for .codehilite in src/static/main.css with what's in styles.css + +## Run with Docker +### Using traefik +If you use traefik, you only have to change the url in the label "traefik.http.routers.sqnotes.rule". You can also modify the labels to rename the service from "sqnotes" to anything else. + +Then start the service. It will create the image and start it for you: +```bash +docker-compose up -d +``` + +### Without using traefik +Simply uncomment lines 13 and 14 to expose port 8080. You can leave the rest. +Then start the container: +```bash +docker-compose up -d +``` + +## Future features, todo +* Replace pickle with sqlite or smth diff --git a/data/notes.pickle b/data/notes.pickle new file mode 100644 index 0000000000000000000000000000000000000000..da9301b3c7c7cacb9d0fb0ab352ac455176166a6 GIT binary patch literal 20702 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 bkNr5+|7>q(Ptq;VWcMyYEH7TygQ)Z0+Rdnk literal 0 HcmV?d00001 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a141c7a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,20 @@ +version: '3' +networks: + traefik_traefik: + external: true + +services: + sqnotes: + build: . + image: sqnotes + volumes: + - ./data:/app/data + restart: always + #ports: + #- 8080:8080 + labels: + - "traefik.http.routers.sqnotes.rule=Host(`notes.squi.fr`)" + - "traefik.http.services.sqnotes.loadbalancer.server.port=8080" + - "traefik.docker.network=traefik_traefik" + networks: + traefik_traefik: diff --git a/squipnotes.png b/squipnotes.png new file mode 100644 index 0000000000000000000000000000000000000000..7721d36951d94eb061950c14ee548dc560e72056 GIT binary patch literal 26288 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 +
{Markup.escape(self.title)}
+
Priority: {self.priority}
+
{self.donemark}
+
+ |||Back +
+
Created : {self.rendertime(self.createtime)} +
Modified : {self.rendertime(self.modtime)}

+
{markdown.markdown(self.text, extensions=['fenced_code', 'codehilite', 'nl2br', 'smarty'])}

+ """ + return Markup(rendered) + + def __str__(self): + return f"{self.title} - {self.donemark} - Priority {self.priority}" diff --git a/src/funcs.py b/src/funcs.py new file mode 100644 index 0000000..62f7600 --- /dev/null +++ b/src/funcs.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python3 +#coding: utf-8 +from classes import task + +def mktaskdir(): + """ + Create our data directory if does not exist. + """ + from os.path import exists + from os import mkdir + + if not exists("./data"): + mkdir("./data") + +def dumptasks(tasks): + """ + Get our tasks list and save them as pickle to tasks.pickle + """ + import pickle + with open('./data/tasks.pickle', 'wb') as mpf: + pickle.dump(tasks, mpf) + + return True + +def gettasks(): + """ + Get our tasks from the file tasks.pickle + """ + from os.path import exists + import pickle + + if exists("./data/tasks.pickle"): + with open('./data/tasks.pickle', 'rb') as mpf: + tasks = pickle.load(mpf) + else: + tasks = [] + + return tasks + +def cattasks(tasklist: list): + """ + Concatenate a list of tasks into a str. + """ + final = "" + for task in tasklist: + final += task.flaskrender() + + return final + +def deltask(timestamp: int): + """ + Delete task in our pickle file for which the createtime corresponds to timestamp + """ + tasks = gettasks() + for task in tasks: + if int(task.createtime) == int(timestamp): + tasks.remove(task) + dumptasks(tasks) + return True + return False + +def findtask(createtime: int): + """ + Find a task in our pickle file of tasks by its createtime + """ + tasks = gettasks() + for task in tasks: + if task.createtime == createtime: + return task + +def addtask(mytask: task): + """ + Add a task to our tasks pickle file (and sort it). + """ + tasks = gettasks() + tasks.append(mytask) + tasks = sorted(tasks, key=lambda task: task.priority, reverse=True) + dumptasks(tasks) + +def exporttasks(): + """ + Export our tasks in markdown, one after the other. + """ + tasks = gettasks() + rawtext = "" + for task in tasks: + rawtext += f"#{task.title}\n" + rawtext += f"* Created: {task.rendertime(task.createtime)}\n" + rawtext += f"* Modified: {task.rendertime(task.modtime)}\n" + rawtext += f"{task.text}\n" + rawtext += f"-----\n\n" + + return rawtext + + return + +def getthemes(): + """ + Find all themes present in our css folder and return a nice list of + css links, for the user to pick into + """ + from flask import url_for + from os import listdir + + allfiles = listdir("./static/styles") + themefiles, themes = [], [] + for myfile in allfiles: + if myfile.endswith(".css"): + themefiles.append(myfile) + + for themefile in themefiles: + themes.append(url_for('static', filename=f'styles/{themefile}')) + + return themes + +def switchstatus(task): + """ + Switches the status of a task from todo to done, or vice-versa + Also updates the modtime + """ + import time + + rightnow = int(time.time()) + if task.donemark == "✅": + task.donemark = "😓" + else: + task.donemark = "✅" + + task.modtime=rightnow + + return task + +def todotasks(tasklist): + """ + Sorts tasks in tasklist: Gives todotasks sorted by priority + """ + buffer = [] + finalstr = "" + for task in tasklist: + if task.donemark == "😓": + buffer.append(task) + + tasks = sorted(buffer, key=lambda task: task.priority, reverse=True) + for task in tasks: + finalstr += task.flaskrender() + + return finalstr + +def donetasks(tasklist): + """ + Sorts tasks in tasklist: Gives done tasks sorted by modtime + """ + buffer = [] + finalstr = "" + for task in tasklist: + if task.donemark == "✅": + buffer.append(task) + + tasks = sorted(buffer, key=lambda task: task.modtime, reverse=True) + for task in tasks: + finalstr += task.flaskrender() + + return finalstr + + + + diff --git a/src/myvenv/bin/Activate.ps1 b/src/myvenv/bin/Activate.ps1 new file mode 100644 index 0000000..b49d77b --- /dev/null +++ b/src/myvenv/bin/Activate.ps1 @@ -0,0 +1,247 @@ +<# +.Synopsis +Activate a Python virtual environment for the current PowerShell session. + +.Description +Pushes the python executable for a virtual environment to the front of the +$Env:PATH environment variable and sets the prompt to signify that you are +in a Python virtual environment. Makes use of the command line switches as +well as the `pyvenv.cfg` file values present in the virtual environment. + +.Parameter VenvDir +Path to the directory that contains the virtual environment to activate. The +default value for this is the parent of the directory that the Activate.ps1 +script is located within. + +.Parameter Prompt +The prompt prefix to display when this virtual environment is activated. By +default, this prompt is the name of the virtual environment folder (VenvDir) +surrounded by parentheses and followed by a single space (ie. '(.venv) '). + +.Example +Activate.ps1 +Activates the Python virtual environment that contains the Activate.ps1 script. + +.Example +Activate.ps1 -Verbose +Activates the Python virtual environment that contains the Activate.ps1 script, +and shows extra information about the activation as it executes. + +.Example +Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv +Activates the Python virtual environment located in the specified location. + +.Example +Activate.ps1 -Prompt "MyPython" +Activates the Python virtual environment that contains the Activate.ps1 script, +and prefixes the current prompt with the specified string (surrounded in +parentheses) while the virtual environment is active. + +.Notes +On Windows, it may be required to enable this Activate.ps1 script by setting the +execution policy for the user. You can do this by issuing the following PowerShell +command: + +PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +For more information on Execution Policies: +https://go.microsoft.com/fwlink/?LinkID=135170 + +#> +Param( + [Parameter(Mandatory = $false)] + [String] + $VenvDir, + [Parameter(Mandatory = $false)] + [String] + $Prompt +) + +<# Function declarations --------------------------------------------------- #> + +<# +.Synopsis +Remove all shell session elements added by the Activate script, including the +addition of the virtual environment's Python executable from the beginning of +the PATH variable. + +.Parameter NonDestructive +If present, do not remove this function from the global namespace for the +session. + +#> +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + + # The prior prompt: + if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { + Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt + Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT + } + + # The prior PYTHONHOME: + if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { + Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME + Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME + } + + # The prior PATH: + if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { + Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH + Remove-Item -Path Env:_OLD_VIRTUAL_PATH + } + + # Just remove the VIRTUAL_ENV altogether: + if (Test-Path -Path Env:VIRTUAL_ENV) { + Remove-Item -Path env:VIRTUAL_ENV + } + + # Just remove VIRTUAL_ENV_PROMPT altogether. + if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) { + Remove-Item -Path env:VIRTUAL_ENV_PROMPT + } + + # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: + if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { + Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force + } + + # Leave deactivate function in the global namespace if requested: + if (-not $NonDestructive) { + Remove-Item -Path function:deactivate + } +} + +<# +.Description +Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the +given folder, and returns them in a map. + +For each line in the pyvenv.cfg file, if that line can be parsed into exactly +two strings separated by `=` (with any amount of whitespace surrounding the =) +then it is considered a `key = value` line. The left hand string is the key, +the right hand is the value. + +If the value starts with a `'` or a `"` then the first and last character is +stripped from the value before being captured. + +.Parameter ConfigDir +Path to the directory that contains the `pyvenv.cfg` file. +#> +function Get-PyVenvConfig( + [String] + $ConfigDir +) { + Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" + + # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). + $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue + + # An empty map will be returned if no config file is found. + $pyvenvConfig = @{ } + + if ($pyvenvConfigPath) { + + Write-Verbose "File exists, parse `key = value` lines" + $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath + + $pyvenvConfigContent | ForEach-Object { + $keyval = $PSItem -split "\s*=\s*", 2 + if ($keyval[0] -and $keyval[1]) { + $val = $keyval[1] + + # Remove extraneous quotations around a string value. + if ("'""".Contains($val.Substring(0, 1))) { + $val = $val.Substring(1, $val.Length - 2) + } + + $pyvenvConfig[$keyval[0]] = $val + Write-Verbose "Adding Key: '$($keyval[0])'='$val'" + } + } + } + return $pyvenvConfig +} + + +<# Begin Activate script --------------------------------------------------- #> + +# Determine the containing directory of this script +$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$VenvExecDir = Get-Item -Path $VenvExecPath + +Write-Verbose "Activation script is located in path: '$VenvExecPath'" +Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" +Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" + +# Set values required in priority: CmdLine, ConfigFile, Default +# First, get the location of the virtual environment, it might not be +# VenvExecDir if specified on the command line. +if ($VenvDir) { + Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" +} +else { + Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." + $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") + Write-Verbose "VenvDir=$VenvDir" +} + +# Next, read the `pyvenv.cfg` file to determine any required value such +# as `prompt`. +$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir + +# Next, set the prompt from the command line, or the config file, or +# just use the name of the virtual environment folder. +if ($Prompt) { + Write-Verbose "Prompt specified as argument, using '$Prompt'" +} +else { + Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" + if ($pyvenvCfg -and $pyvenvCfg['prompt']) { + Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" + $Prompt = $pyvenvCfg['prompt']; + } + else { + Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)" + Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" + $Prompt = Split-Path -Path $venvDir -Leaf + } +} + +Write-Verbose "Prompt = '$Prompt'" +Write-Verbose "VenvDir='$VenvDir'" + +# Deactivate any currently active virtual environment, but leave the +# deactivate function in place. +deactivate -nondestructive + +# Now set the environment variable VIRTUAL_ENV, used by many tools to determine +# that there is an activated venv. +$env:VIRTUAL_ENV = $VenvDir + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } + $env:VIRTUAL_ENV_PROMPT = $Prompt +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" diff --git a/src/myvenv/bin/activate b/src/myvenv/bin/activate new file mode 100644 index 0000000..c77f8fb --- /dev/null +++ b/src/myvenv/bin/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="/home/justine/Sandbox/Python/SquiNotes/myvenv" +export VIRTUAL_ENV + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/bin:$PATH" +export PATH + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "${PYTHONHOME:-}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then + _OLD_VIRTUAL_PS1="${PS1:-}" + PS1="(myvenv) ${PS1:-}" + export PS1 + VIRTUAL_ENV_PROMPT="(myvenv) " + 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/src/myvenv/bin/activate.csh b/src/myvenv/bin/activate.csh new file mode 100644 index 0000000..509b25d --- /dev/null +++ b/src/myvenv/bin/activate.csh @@ -0,0 +1,26 @@ +# This file must be used with "source bin/activate.csh" *from csh*. +# You cannot run it directly. +# Created by Davide Di Blasi . +# Ported to Python 3.3 venv by Andrew Svetlov + +alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate' + +# Unset irrelevant variables. +deactivate nondestructive + +setenv VIRTUAL_ENV "/home/justine/Sandbox/Python/SquiNotes/myvenv" + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/bin:$PATH" + + +set _OLD_VIRTUAL_PROMPT="$prompt" + +if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then + set prompt = "(myvenv) $prompt" + setenv VIRTUAL_ENV_PROMPT "(myvenv) " +endif + +alias pydoc python -m pydoc + +rehash diff --git a/src/myvenv/bin/activate.fish b/src/myvenv/bin/activate.fish new file mode 100644 index 0000000..e03808b --- /dev/null +++ b/src/myvenv/bin/activate.fish @@ -0,0 +1,66 @@ +# This file must be used with "source /bin/activate.fish" *from fish* +# (https://fishshell.com/); you cannot run it directly. + +function deactivate -d "Exit virtual environment and return to normal shell environment" + # reset old environment variables + if test -n "$_OLD_VIRTUAL_PATH" + set -gx PATH $_OLD_VIRTUAL_PATH + set -e _OLD_VIRTUAL_PATH + end + if test -n "$_OLD_VIRTUAL_PYTHONHOME" + set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME + set -e _OLD_VIRTUAL_PYTHONHOME + end + + if test -n "$_OLD_FISH_PROMPT_OVERRIDE" + functions -e fish_prompt + set -e _OLD_FISH_PROMPT_OVERRIDE + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + end + + set -e VIRTUAL_ENV + set -e VIRTUAL_ENV_PROMPT + if test "$argv[1]" != "nondestructive" + # Self-destruct! + functions -e deactivate + end +end + +# Unset irrelevant variables. +deactivate nondestructive + +set -gx VIRTUAL_ENV "/home/justine/Sandbox/Python/SquiNotes/myvenv" + +set -gx _OLD_VIRTUAL_PATH $PATH +set -gx PATH "$VIRTUAL_ENV/bin" $PATH + +# Unset PYTHONHOME if set. +if set -q PYTHONHOME + set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME + set -e PYTHONHOME +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # fish uses a function instead of an env var to generate the prompt. + + # Save the current fish_prompt function as the function _old_fish_prompt. + functions -c fish_prompt _old_fish_prompt + + # With the original prompt function renamed, we can override with our own. + function fish_prompt + # Save the return status of the last command. + set -l old_status $status + + # Output the venv prompt; color taken from the blue of the Python logo. + printf "%s%s%s" (set_color 4B8BBE) "(myvenv) " (set_color normal) + + # Restore the return status of the previous command. + echo "exit $old_status" | . + # Output the original/"old" prompt. + _old_fish_prompt + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" + set -gx VIRTUAL_ENV_PROMPT "(myvenv) " +end diff --git a/src/myvenv/bin/flask b/src/myvenv/bin/flask new file mode 100755 index 0000000..8b23315 --- /dev/null +++ b/src/myvenv/bin/flask @@ -0,0 +1,8 @@ +#!/home/justine/Sandbox/Python/SquiNotes/myvenv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from flask.cli import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/src/myvenv/bin/pip b/src/myvenv/bin/pip new file mode 100755 index 0000000..400b618 --- /dev/null +++ b/src/myvenv/bin/pip @@ -0,0 +1,8 @@ +#!/home/justine/Sandbox/Python/SquiNotes/myvenv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/src/myvenv/bin/pip3 b/src/myvenv/bin/pip3 new file mode 100755 index 0000000..400b618 --- /dev/null +++ b/src/myvenv/bin/pip3 @@ -0,0 +1,8 @@ +#!/home/justine/Sandbox/Python/SquiNotes/myvenv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/src/myvenv/bin/pip3.10 b/src/myvenv/bin/pip3.10 new file mode 100755 index 0000000..400b618 --- /dev/null +++ b/src/myvenv/bin/pip3.10 @@ -0,0 +1,8 @@ +#!/home/justine/Sandbox/Python/SquiNotes/myvenv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/src/myvenv/bin/python b/src/myvenv/bin/python new file mode 120000 index 0000000..b8a0adb --- /dev/null +++ b/src/myvenv/bin/python @@ -0,0 +1 @@ +python3 \ No newline at end of file diff --git a/src/myvenv/bin/python3 b/src/myvenv/bin/python3 new file mode 120000 index 0000000..ae65fda --- /dev/null +++ b/src/myvenv/bin/python3 @@ -0,0 +1 @@ +/usr/bin/python3 \ No newline at end of file diff --git a/src/myvenv/bin/python3.10 b/src/myvenv/bin/python3.10 new file mode 120000 index 0000000..b8a0adb --- /dev/null +++ b/src/myvenv/bin/python3.10 @@ -0,0 +1 @@ +python3 \ No newline at end of file diff --git a/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/INSTALLER b/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/LICENSE.rst b/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/LICENSE.rst new file mode 100644 index 0000000..9d227a0 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.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/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/METADATA b/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/METADATA new file mode 100644 index 0000000..d617f5f --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/METADATA @@ -0,0 +1,125 @@ +Metadata-Version: 2.1 +Name: Flask +Version: 2.0.3 +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 +Platform: UNKNOWN +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.6 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst +Requires-Dist: Werkzeug (>=2.0) +Requires-Dist: Jinja2 (>=3.0) +Requires-Dist: itsdangerous (>=2.0) +Requires-Dist: click (>=7.1.2) +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/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/RECORD b/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/RECORD new file mode 100644 index 0000000..04004fd --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/RECORD @@ -0,0 +1,52 @@ +../../../bin/flask,sha256=6BbsyJvmjHsBPkzEhen_WsMUjsYDS4upOEjjMISdMUc,249 +Flask-2.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Flask-2.0.3.dist-info/LICENSE.rst,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +Flask-2.0.3.dist-info/METADATA,sha256=jK50YtxZfODLQP_GF1sNH6dOXRCI5bBLrAc7pWQwuXw,3839 +Flask-2.0.3.dist-info/RECORD,, +Flask-2.0.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +Flask-2.0.3.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +Flask-2.0.3.dist-info/entry_points.txt,sha256=s3MqQpduU25y4dq3ftBYD6bMVdVnbMpZP-sUNw0zw0k,41 +Flask-2.0.3.dist-info/top_level.txt,sha256=dvi65F6AeGWVU0TBpYiC04yM60-FX1gJFkK31IKQr5c,6 +flask/__init__.py,sha256=ubQS5Xt6LMjPSwGO3Jksi5yx8AyuU0vT_VdHjt0j97A,2251 +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=ectBbi9hGmVHAse5TNcFQZIDRkDAxYUAnLgfuKD0Xws,81975 +flask/blueprints.py,sha256=AkAVXZ_MMkjwjklzCAMdBNowTiM0wVQPynnUnXjTL2M,23781 +flask/cli.py,sha256=9v7FDIwWZ3QZsR6ka-qMYzMxSThfmQ4PEA4lkI38R6c,32287 +flask/config.py,sha256=70Uyjh1Jzb9MfTCT7NDhuZWAzyIEu-TIyk6-22MP3zQ,11285 +flask/ctx.py,sha256=Rmw5VOFQdbomLoCQPbU_0FbQkuB56CtpnQVU4yzXYB8,17589 +flask/debughelpers.py,sha256=W82-xrRmodjopBngI9roYH-q08EbQwN2HEGfDAi6SA0,6184 +flask/globals.py,sha256=cWd-R2hUH3VqPhnmQNww892tQS6Yjqg_wg8UvW1M7NM,1723 +flask/helpers.py,sha256=kstplLDtD0Isobilp87Lfmwq1tk2spnHjUf_O5-EhoE,30618 +flask/json/__init__.py,sha256=_YIqOsy8YOSyoLbplFtNcKvF5kwNKenmJ87Ub2Myc0k,12104 +flask/json/__pycache__/__init__.cpython-310.pyc,, +flask/json/__pycache__/tag.cpython-310.pyc,, +flask/json/tag.py,sha256=fys3HBLssWHuMAIJuTcf2K0bCtosePBKXIWASZEEjnU,8857 +flask/logging.py,sha256=1o_hirVGqdj7SBdETnhX7IAjklG89RXlrwz_2CjzQQE,2273 +flask/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +flask/scaffold.py,sha256=fM9mRy7QBh9fhJ0VTogVx900dDa5oxz8FOw6OK5F-TU,32796 +flask/sessions.py,sha256=46jK4JlcdeBiYbDWTZJn_6u8EqDV-ByRdhlKrbgFi5M,15714 +flask/signals.py,sha256=H7QwDciK-dtBxinjKpexpglP0E6k0MJILiFWTItfmqU,2136 +flask/templating.py,sha256=l96VD39JQ0nue4Bcj7wZ4-FWWs-ppLxvgBCpwDQ4KAk,5626 +flask/testing.py,sha256=T3mr2PLQEkfxoftSTxmGfTtb_FSX3PgfGT8DUGNPWuk,10840 +flask/typing.py,sha256=L5JMltVjj8fovGS1hrMpb13IPfsFDESCCnpRN5CPT4U,1844 +flask/views.py,sha256=nhq31TRB5Z-z2mjFGZACaaB2Et5XPCmWhWxJxOvLWww,5948 +flask/wrappers.py,sha256=VndbHPRBSUUOejmd2Y3ydkoCVUtsS2OJIdJEVIkBVD8,5604 diff --git a/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/REQUESTED b/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/WHEEL b/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/WHEEL new file mode 100644 index 0000000..becc9a6 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Flask-2.0.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/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/entry_points.txt b/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/entry_points.txt new file mode 100644 index 0000000..137232d --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +flask = flask.cli:main diff --git a/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/top_level.txt b/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/top_level.txt new file mode 100644 index 0000000..7e10602 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Flask-2.0.3.dist-info/top_level.txt @@ -0,0 +1 @@ +flask diff --git a/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/INSTALLER b/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/LICENSE.rst b/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/LICENSE.rst new file mode 100644 index 0000000..c37cae4 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.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/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/METADATA b/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/METADATA new file mode 100644 index 0000000..3b9355a --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/METADATA @@ -0,0 +1,113 @@ +Metadata-Version: 2.1 +Name: Jinja2 +Version: 3.0.3 +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.6 +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/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/RECORD b/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/RECORD new file mode 100644 index 0000000..077ce0d --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/RECORD @@ -0,0 +1,58 @@ +Jinja2-3.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Jinja2-3.0.3.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 +Jinja2-3.0.3.dist-info/METADATA,sha256=uvKoBSMLvh0qHK-6khEqSe1yOV4jxFzbPSREOp-3BXk,3539 +Jinja2-3.0.3.dist-info/RECORD,, +Jinja2-3.0.3.dist-info/WHEEL,sha256=ewwEueio1C2XeHTvT17n8dZUJgOvyCWCt0WVNLClP9o,92 +Jinja2-3.0.3.dist-info/entry_points.txt,sha256=Qy_DkVo6Xj_zzOtmErrATe8lHZhOqdjpt3e4JJAGyi8,61 +Jinja2-3.0.3.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7 +jinja2/__init__.py,sha256=V3JjnTV-nyIHN6rwj03N1M11fegjGvv-weiHMQwH1pk,2205 +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=EdgGJKi7O1yvr4yFlvqPNEqV6M1qHyQr8Gt8GmVTKVM,1775 +jinja2/async_utils.py,sha256=jBcJSmLoQa2PjJdNcOpwaUmBxFNE9rZNwMF7Ob3dP9I,1947 +jinja2/bccache.py,sha256=v5rKAlYxIvfJEa0uGzAC6yCYSS3KuXT5Eqi-n9qvNi8,12670 +jinja2/compiler.py,sha256=v7zKz-mgSYXmfXD9mRmi2BU0B6Z-1RGZmOXCrsPKzc0,72209 +jinja2/constants.py,sha256=GMoFydBF_kdpaRKPoM5cl5MviquVRLVyZtfp5-16jg0,1433 +jinja2/debug.py,sha256=r0JL0vfO7HPlyKZEdr6eVlg7HoIg2OQGmJ7SeUEyAeI,8494 +jinja2/defaults.py,sha256=boBcSw78h-lp20YbaXSJsqkAI2uN_mD_TtCydpeq5wU,1267 +jinja2/environment.py,sha256=Vz20npBX5-SUH_eguQuxrSQDEsLFjho0qcHLdMhY3hA,60983 +jinja2/exceptions.py,sha256=ioHeHrWwCWNaXX1inHmHVblvc4haO7AXsjCp3GfWvx0,5071 +jinja2/ext.py,sha256=44SjDjeYkkxQTpmC2BetOTxEFMgQ42p2dfSwXmPFcSo,32122 +jinja2/filters.py,sha256=jusKTZbd0ddZMaibZkxMUVKNsOsaYtOq_Il8Imtx4BE,52609 +jinja2/idtracking.py,sha256=WekexMql3u5n3vDxFsQ_i8HW0j24AtjWTjrPBLWrHww,10721 +jinja2/lexer.py,sha256=qNEQqDQw_zO5EaH6rFQsER7Qwn2du0o22prB-TR11HE,29930 +jinja2/loaders.py,sha256=1MjXJOU6p4VywFqtpDZhtvtT_vIlmHnZKMKHHw4SZzA,22754 +jinja2/meta.py,sha256=GNPEvifmSaU3CMxlbheBOZjeZ277HThOPUTf1RkppKQ,4396 +jinja2/nativetypes.py,sha256=KCJl71MogrDih_BHBu6xV5p7Cr_jggAgu-shKTg6L28,3969 +jinja2/nodes.py,sha256=i34GPRAZexXMT6bwuf5SEyvdmS-bRCy9KMjwN5O6pjk,34550 +jinja2/optimizer.py,sha256=tHkMwXxfZkbfA1KmLcqmBMSaz7RLIvvItrJcPoXTyD8,1650 +jinja2/parser.py,sha256=kHnU8v92GwMYkfr0MVakWv8UlSf_kJPx8LUsgQMof70,39767 +jinja2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +jinja2/runtime.py,sha256=wVRlkEmAgNU67AIQDqLvI6UkNLkzDqpLA-z4Mi3vl3g,35054 +jinja2/sandbox.py,sha256=-8zxR6TO9kUkciAVFsIKu8Oq-C7PTeYEdZ5TtA55-gw,14600 +jinja2/tests.py,sha256=Am5Z6Lmfr2XaH_npIfJJ8MdXtWsbLjMULZJulTAj30E,5905 +jinja2/utils.py,sha256=udQxWIKaq4QDCZiXN31ngKOaGGdaMA5fl0JMaM-F6fg,26971 +jinja2/visitor.py,sha256=ZmeLuTj66ic35-uFH-1m0EKXiw4ObDDb_WuE6h5vPFg,3572 diff --git a/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/WHEEL b/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/WHEEL new file mode 100644 index 0000000..5bad85f --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/entry_points.txt b/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/entry_points.txt new file mode 100644 index 0000000..3619483 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[babel.extractors] +jinja2 = jinja2.ext:babel_extract [i18n] + diff --git a/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/top_level.txt b/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/top_level.txt new file mode 100644 index 0000000..7f7afbf --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Jinja2-3.0.3.dist-info/top_level.txt @@ -0,0 +1 @@ +jinja2 diff --git a/src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/INSTALLER b/src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/LICENSE.rst b/src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/LICENSE.rst new file mode 100644 index 0000000..9d227a0 --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/METADATA b/src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/METADATA new file mode 100644 index 0000000..485a5e0 --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/RECORD b/src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/RECORD new file mode 100644 index 0000000..2f4cfc9 --- /dev/null +++ b/src/myvenv/lib/python3.10/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=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +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=6B0vZ-Dd34LpGZN_4Y_GbBSl1fSb7keGXRzuHUFcOBA,152 +MarkupSafe-2.1.1.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11 +markupsafe/__init__.py,sha256=xfaUQkKNRTdYWe6HnnJ2HjguFmS-C_0H6g8-Q9VAfkQ,9284 +markupsafe/__pycache__/__init__.cpython-310.pyc,, +markupsafe/__pycache__/_native.cpython-310.pyc,, +markupsafe/_native.py,sha256=GR86Qvo_GcgKmKreA1WmYN9ud17OFwkww8E-fiW-57s,1713 +markupsafe/_speedups.c,sha256=X2XvQVtIdcK4Usz70BvkzoOfjTCmQlDkkjYSn-swE0g,7083 +markupsafe/_speedups.cpython-310-x86_64-linux-gnu.so,sha256=MK7Cz4YNHiq95odgpldQy_64gBMHWU12vH7ZlN8KikE,44224 +markupsafe/_speedups.pyi,sha256=vfMCsOgbAXRNLUXkyuyonG8uEWKYU4PDqNuMaDELAYw,229 +markupsafe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/WHEEL b/src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/WHEEL new file mode 100644 index 0000000..df5f4fa --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.0) +Root-Is-Purelib: false +Tag: cp310-cp310-manylinux_2_17_x86_64 +Tag: cp310-cp310-manylinux2014_x86_64 + diff --git a/src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/top_level.txt b/src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/top_level.txt new file mode 100644 index 0000000..75bf729 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/MarkupSafe-2.1.1.dist-info/top_level.txt @@ -0,0 +1 @@ +markupsafe diff --git a/src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/INSTALLER b/src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/LICENSE.rst b/src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/LICENSE.rst new file mode 100644 index 0000000..c37cae4 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.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/src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/METADATA b/src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/METADATA new file mode 100644 index 0000000..551fa0b --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/METADATA @@ -0,0 +1,129 @@ +Metadata-Version: 2.1 +Name: Werkzeug +Version: 2.0.3 +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 +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 :: 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.6 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst +Requires-Dist: dataclasses ; python_version < "3.7" +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/src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/RECORD b/src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/RECORD new file mode 100644 index 0000000..df23d62 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/RECORD @@ -0,0 +1,111 @@ +Werkzeug-2.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Werkzeug-2.0.3.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 +Werkzeug-2.0.3.dist-info/METADATA,sha256=Rxzda7JFgpyr7oqR42Z57bNxRp-pjna_KYhcivqvXY4,4452 +Werkzeug-2.0.3.dist-info/RECORD,, +Werkzeug-2.0.3.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +Werkzeug-2.0.3.dist-info/top_level.txt,sha256=QRyj2VjwJoQkrwjwFIOlB8Xg3r9un0NtqVHQF-15xaw,9 +werkzeug/__init__.py,sha256=2frslFsD2EbmZUTfzZ5njDmic66S5f6XMdT24AOGYhk,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__/filesystem.cpython-310.pyc,, +werkzeug/__pycache__/formparser.cpython-310.pyc,, +werkzeug/__pycache__/http.cpython-310.pyc,, +werkzeug/__pycache__/local.cpython-310.pyc,, +werkzeug/__pycache__/routing.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__/useragents.cpython-310.pyc,, +werkzeug/__pycache__/utils.cpython-310.pyc,, +werkzeug/__pycache__/wsgi.cpython-310.pyc,, +werkzeug/_internal.py,sha256=_0GZM3B6gE4eoRTp9K6T7spvY5qJQ9Od9GRIp4lZpzU,18572 +werkzeug/_reloader.py,sha256=B1hEfgsUOz2IginBQM5Zak_eaIF7gr3GS5-0x2OHvAE,13950 +werkzeug/datastructures.py,sha256=m79A8rHQEt5B7qVqyrjARXzHL66Katn8S92urGscTw4,97929 +werkzeug/datastructures.pyi,sha256=uFOqffFoaOEa-43IPlK9otu1X4lDOoqIgG4ULS0ObiE,34119 +werkzeug/debug/__init__.py,sha256=Vn0WQfD9w6DGg1j_2gWpSKKTaFlwxhbCBwi7QQMz1s8,17917 +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=jJjid1dIlCNWbDHXTtjJW5XqNfPjSOKbtUmEX5weNdY,5976 +werkzeug/debug/repr.py,sha256=QCSHENKsChEZDCIApkVi_UNjhJ77v8BMXK1OfxO189M,9483 +werkzeug/debug/shared/FONT_LICENSE,sha256=LwAVEI1oYnvXiNMT9SnCH_TaLCxCpeHziDrMg0gPkAI,4673 +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/source.png,sha256=RoGcBTE4CyCB85GBuDGTFlAnUqxwTBiIfDqW15EpnUQ,818 +werkzeug/debug/shared/style.css,sha256=h1ZSUVaKNpfbfcYzRb513WAhPySGDQom1uih3uEDxPw,6704 +werkzeug/debug/shared/ubuntu.ttf,sha256=1eaHFyepmy4FyDvjLVzpITrGEBu_CZYY94jE0nED1c0,70220 +werkzeug/debug/tbtools.py,sha256=khUCWQcpbxzeOs5NlT-E9n99BI-ELH9K9RY5exc-X_o,19362 +werkzeug/exceptions.py,sha256=WLCqXBEHm5Xj2d2sfON9XIneeRS3MlNXKH85k1AQIJU,28776 +werkzeug/filesystem.py,sha256=JS2Dv2QF98WILxY4_thHl-WMcUcwluF_4igkDPaP1l4,1956 +werkzeug/formparser.py,sha256=X-p3Ek4ji8XrKrbmaWxr8StLSc6iuksbpIeweaabs4s,17400 +werkzeug/http.py,sha256=Xm3WhYKRQKh_J12514F8y8prILldXceOceeO8EiQEZI,45222 +werkzeug/local.py,sha256=5HbGdD0vVNJgXH3SXfkMjdxIpzy7iqkHJMGCNjljFNo,23664 +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=sAg3GcOhICIkwYX5bJGG8n8iebX0Yipq_UH0HvrBvoU,13964 +werkzeug/middleware/profiler.py,sha256=QkXk7cqnaPnF8wQu-5SyPCIOT3_kdABUBorQOghVNOA,4899 +werkzeug/middleware/proxy_fix.py,sha256=l7LC_LDu0Yd4SvUxS5SFigAJMzcIOGm6LNKl9IXJBSU,6974 +werkzeug/middleware/shared_data.py,sha256=xydEqOhAGg0aQJEllPDVfz2-8jHwWvJpAxfPsfPCu7k,10960 +werkzeug/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +werkzeug/routing.py,sha256=rATL0ZkbTBgvdgJp6WgihuwKyivCF8K4a8kQ4hFgY6A,84581 +werkzeug/sansio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +werkzeug/sansio/__pycache__/__init__.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/multipart.py,sha256=BRjBk_mCPjSJzwNVvBgmrJGk3QxA9pYfsgzFki28bxc,8751 +werkzeug/sansio/request.py,sha256=kt7fizz15HPuYKYU1_3TTEkNSuXeeaM4aLcjW84qvv4,20247 +werkzeug/sansio/response.py,sha256=zvCq9HSBBZGBd5Gg412BY9RZIwnKsJl5Kzfd3Kl9sSo,26098 +werkzeug/sansio/utils.py,sha256=V5v-UUnX8pm4RehP9Tt_NiUSOJGJGUvKjlW0eOIQldM,4164 +werkzeug/security.py,sha256=gPDRuCjkjWrcqj99tBMq8_nHFZLFQjgoW5Ga5XIw9jo,8158 +werkzeug/serving.py,sha256=6aV-RKbZm4rUHveQGuh4SY0wFZTmXyR43yD_kCQm8Wo,38287 +werkzeug/test.py,sha256=eUORFaeIDXcmncLdYxgFqYiVdolZkYRY67QV1_ATk20,48235 +werkzeug/testapp.py,sha256=f48prWSGJhbSrvYb8e1fnAah4BkrLb0enHSdChgsjBY,9471 +werkzeug/urls.py,sha256=Du2lreBHvgBh5c2_bcx72g3hzV2ZabXYZsp-picUIJs,41023 +werkzeug/user_agent.py,sha256=WclZhpvgLurMF45hsioSbS75H1Zb4iMQGKN3_yZ2oKo,1420 +werkzeug/useragents.py,sha256=G8tmv_6vxJaPrLQH3eODNgIYe0_V6KETROQlJI-WxDE,7264 +werkzeug/utils.py,sha256=D_dnCLUfodQ4k0GRSpnI6qDoVoaX7-Dza57bx7sabG0,37101 +werkzeug/wrappers/__init__.py,sha256=-s75nPbyXHzU_rwmLPDhoMuGbEUk0jZT_n0ZQAOFGf8,654 +werkzeug/wrappers/__pycache__/__init__.cpython-310.pyc,, +werkzeug/wrappers/__pycache__/accept.cpython-310.pyc,, +werkzeug/wrappers/__pycache__/auth.cpython-310.pyc,, +werkzeug/wrappers/__pycache__/base_request.cpython-310.pyc,, +werkzeug/wrappers/__pycache__/base_response.cpython-310.pyc,, +werkzeug/wrappers/__pycache__/common_descriptors.cpython-310.pyc,, +werkzeug/wrappers/__pycache__/cors.cpython-310.pyc,, +werkzeug/wrappers/__pycache__/etag.cpython-310.pyc,, +werkzeug/wrappers/__pycache__/json.cpython-310.pyc,, +werkzeug/wrappers/__pycache__/request.cpython-310.pyc,, +werkzeug/wrappers/__pycache__/response.cpython-310.pyc,, +werkzeug/wrappers/__pycache__/user_agent.cpython-310.pyc,, +werkzeug/wrappers/accept.py,sha256=NzyLfKH3qC5cSbkEc5azw5-lp_kU8JIrtc8AdGQ0HBs,413 +werkzeug/wrappers/auth.py,sha256=ArJiEn8HHzy1B7wUGuN7s3AHpnClKlaDY0F7N7QZSLA,824 +werkzeug/wrappers/base_request.py,sha256=saz9RyNQkvI_XLPYVm29KijNHmD1YzgxDqa0qHTbgss,1174 +werkzeug/wrappers/base_response.py,sha256=q_-TaYywT5G4zA-DWDRDJhJSat2_4O7gOPob6ye4_9A,1186 +werkzeug/wrappers/common_descriptors.py,sha256=aeVFTsTb0HJn5O8zF6WwELEDDULdOLFkWaUrvD1Huds,866 +werkzeug/wrappers/cors.py,sha256=9Ho7aXd64sB2Msz71jRXAdAI8UyqIJgv-CJsnlfUSzM,814 +werkzeug/wrappers/etag.py,sha256=7SI34rtlXJHyJlqe8B0dFu4ouo6L0DJmYyqwWoY79oc,814 +werkzeug/wrappers/json.py,sha256=h_XfBZV5ZETkHYgONuoSyB9KXR9W90mgBh_mFUysp6c,394 +werkzeug/wrappers/request.py,sha256=I77nwHgCzynmgwJVNw7bo7MfTU_CusNBO0b4TjpIRdQ,24790 +werkzeug/wrappers/response.py,sha256=c24tBeq8G5RwPCU5iCJvJPaKyUEIrfMiWO4yGtTOwmI,35214 +werkzeug/wrappers/user_agent.py,sha256=IMUJCFohZSMsBTmqyJZtjG5y4sB1zxQBE690bixb6uY,419 +werkzeug/wsgi.py,sha256=L7s5-Rlt7BRVEZ1m81MaenGfMDP7yL3p1Kxt9Yssqzg,33727 diff --git a/src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/WHEEL b/src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/WHEEL new file mode 100644 index 0000000..becc9a6 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.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/src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/top_level.txt b/src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/top_level.txt new file mode 100644 index 0000000..6fe8da8 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/Werkzeug-2.0.3.dist-info/top_level.txt @@ -0,0 +1 @@ +werkzeug diff --git a/src/myvenv/lib/python3.10/site-packages/_distutils_hack/__init__.py b/src/myvenv/lib/python3.10/site-packages/_distutils_hack/__init__.py new file mode 100644 index 0000000..5f40996 --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/_distutils_hack/__pycache__/__init__.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/_distutils_hack/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7b18a28c23ea8b61be3b6094b20ee3fbb2364472 GIT binary patch literal 5140 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 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/_distutils_hack/override.py b/src/myvenv/lib/python3.10/site-packages/_distutils_hack/override.py new file mode 100644 index 0000000..2cc433a --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/_distutils_hack/override.py @@ -0,0 +1 @@ +__import__('_distutils_hack').do_override() diff --git a/src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/INSTALLER b/src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/LICENSE.rst b/src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/LICENSE.rst new file mode 100644 index 0000000..d12a849 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/click-8.0.4.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/src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/METADATA b/src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/METADATA new file mode 100644 index 0000000..74471c7 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/METADATA @@ -0,0 +1,111 @@ +Metadata-Version: 2.1 +Name: click +Version: 8.0.4 +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.6 +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/src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/RECORD b/src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/RECORD new file mode 100644 index 0000000..2b7d742 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/RECORD @@ -0,0 +1,41 @@ +click-8.0.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +click-8.0.4.dist-info/LICENSE.rst,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 +click-8.0.4.dist-info/METADATA,sha256=zcuHOwCuWGOxyQO9MNOlHVHnEqfFAUi2lHHEpCMtLJw,3247 +click-8.0.4.dist-info/RECORD,, +click-8.0.4.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +click-8.0.4.dist-info/top_level.txt,sha256=J1ZQogalYS4pphY_lPECoNMfw0HzTSrZglC4Yfwo4xA,6 +click/__init__.py,sha256=bOKrvMqmR9rN07vN_ycyrdF-EcTCl-EmuAjq-Fp4yPM,3243 +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__/_unicodefun.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/_unicodefun.py,sha256=JKSh1oSwG_zbjAu4TBCa9tQde2P9FiYcf4MBfy5NdT8,3201 +click/_winconsole.py,sha256=5ju3jQkcZD0W27WEMGqmEP4y_crUVzPCqsX_FYb7BO0,7860 +click/core.py,sha256=MYYmvqVa_dh4x4f-mr7VyNi6197ucYbJ0fsWW5EnCrA,111432 +click/decorators.py,sha256=5ZngOD72Flo8VLN29iarI0A5u_F-dxmqtUqx4KN8hOg,14879 +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=HHH0wMwlDW4WQhs8rRcS9M8MAo9gltGBN6V2PEbsTp0,18003 +click/termui.py,sha256=mZ12uc3-loFaV__vr8buxn9uIjAhy7QwVuZOQ8jDdjc,28873 +click/testing.py,sha256=ptpMYgRY7dVfE3UDgkgwayu9ePw98sQI3D7zZXiCpj4,16063 +click/types.py,sha256=rj2g3biAXKkNKV8vlwbIKSUlixhXybH84N84fwCYqUU,35092 +click/utils.py,sha256=M8tuplcFFHROha3vQ60ZRSakSB_ng6w9e8Uc1AugPZ0,18934 diff --git a/src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/WHEEL b/src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/WHEEL new file mode 100644 index 0000000..becc9a6 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/click-8.0.4.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/src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/top_level.txt b/src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/top_level.txt new file mode 100644 index 0000000..dca9a90 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/click-8.0.4.dist-info/top_level.txt @@ -0,0 +1 @@ +click diff --git a/src/myvenv/lib/python3.10/site-packages/click/__init__.py b/src/myvenv/lib/python3.10/site-packages/click/__init__.py new file mode 100644 index 0000000..35176c7 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/click/__init__.py @@ -0,0 +1,75 @@ +""" +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 get_terminal_size as get_terminal_size +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_os_args as get_os_args +from .utils import get_text_stream as get_text_stream +from .utils import open_file as open_file + +__version__ = "8.0.4" diff --git a/src/myvenv/lib/python3.10/site-packages/click/__pycache__/__init__.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/click/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c7e303f6da9e5358f92c03ccebb257e4d3790596 GIT binary patch literal 2703 zcmc)M*-{%v6b4`clF-J!n4K{gV>XG^>}C;*vDwPN&8bvPjYf^sVYYOSSo{cilT=>2a|EU;(Mi?GO^LodM+JBwb1Wp)m|0xRr! z=cBs{tLz2z8mzGw(d)3zUP5oc274L337hN{^cHNfKccr`o4tzu1fSSz=pEQ$ucLQi zm%V}BgFW^pdLQ=LTj)IG+1uy?IADKr4&5U-V(*}j;h4RP{tTbld*~B5Veg~Az!!EN z{T05l574J@iavz1;?Y%P>iBy#m3O3lXGm>WhL&#N2;=f8Ec>3}`o#*iq^AR^MA0Zb z8DUu%IxIS}VE928SV{{c^bOa#6R8I!L+ON4{Lh-sK4{X@y477uxXrkR}(#gAB{KEUsIz%eZ(+ z+6JvCbqbFMzP1XE$fo{oz|V!LhH7F@l`5|ALUei`7s}VJ5Sz`f?09D0cN}4d()Vh| zy-+;T$k;JnT!6@&Rh&@14vb#}&u1quEoHeP6besESg)%#+b=72*}iuxm21%$6N^|| zC{}u&JzW+~@Y>%+r8NUfYqKb9Us<6~lgD2MX80IR`h1xQZu^Cw@vJuTgRhFO^R?a! zrT@F~Ucpy%gYElPv0kYgZIuM}wPIiG_Ub(u?D_FFTY38&KH8#wE6F42h(o3LLfg-z z*0?Kv9FjTrukeL?DO-x?u8(N>j0HIIsY10vCLfd)n9sM@RT80TSCqn+(|o<_Ol>k; zMRW0Ewj(Sm6jq+gP4^<~vTxo?3(HyJv!bFX>CQW7Qe4cHp5>TYey3Y+#!kD;lf)gX z;@M^Fj0ILj)6sOG{E`w{7iwo<(+zl=Xj+C&)!~!F6IHxAqx%;Zr+6%$FZ8fqG>!*N+Us@quWBls++sXMc zO>|wsw=*JrbAI{lB7b;wb$Ecy=*`Uu|9`&Jwp%W@d5i0NxPfT|mBb1HvnZ*IT%iJ% zM?IN3RKjxW=lI&hjjplTR;%J;_g7$KRhoM7D?voHP_$CCQM6NZP;^psQFK%EU{q70 zzE`#CrQSCbeH8r^0~CW4LlnalBN&jXRf#_1)F|~D7`ROwzhF69y`@$>;2o&OumN$} zQWdGjv7z2kOi;Y1n56hXF-0*=F+(v+F-MW5$YE4tA-=*|%~Qt$#UjNL#WKYT#Yc)& ziZzOLiVccQiYPm!lMz^JB8v;Jve{uWVZbb#WYpK@jV z7|#7%(O3+TyTZ@jg8!JSJvMSzzf|P89}1mwpYDZspTnm`F5pMXQg&fJr)4PS0?WR` rccISN^z_M@ru1ZJn%Ur~n%Js6c<>pDU+aFwh( literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/click/__pycache__/_compat.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/click/__pycache__/_compat.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0d97cad84a8ed6d01f1daad06c0a66191917646b GIT binary patch literal 15764 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 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/click/__pycache__/_termui_impl.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/click/__pycache__/_termui_impl.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7ef6d61f833fd0358ac7accb756a1a32d4766c92 GIT binary patch literal 16088 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 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/click/__pycache__/_textwrap.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/click/__pycache__/_textwrap.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dfdc359ee24587b1cd1cc10f29d7cee03d6120b1 GIT binary patch literal 1563 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�I-x1RWtgL35_IjMpj2)M&H9sH&2dyqNt$n(4mvc^|FiS1>Y?SD8wtxT^u?z`3OfN3oo-H|1p-p^7T}BmAx}bPd?&YZ_ zwh5OmcmF`-72796o34{a(ERTpe4Yg$Cqdz|rkX#?nc}z5_0s)|U#IEY09|gy_kr)T zyCQ>8c~OQLuv=bUI>@i+(C|HW#bat7;j{k`pWa6BA4K%q1b!Fb|Hzv7k_OVnE%`y* z`TyewvUo-_N`8JH7#yF>>B!~E=qxmBBp%U2CA)xPO}v)kEAbJ0{&ckF-$U^f#*_urm}(dwwmd zyofCtk-bB;Sb1mOL*^#PK13P-NAVTma)pzMGbyL;JJo3D3s6e4q-uz!rPTq7_jZ$d zP8EMjvv>fZDdTwmP)I@!aPNMiGEaai(S|DCL{6`6qW(cKG~Q!~$#ELuT0l3nyqR%U zI`VU(9;ZAXcB^!Bs`8;v5tryzqr9KakMN@p9P2H)-A7oqi~a_o(ba55`L$&K56~Uz zIKJpOTr`nN%JZR}i9e(7Ms1^2m2vh_D>y5y0EJL0ob}GEt62D#mEz|y-ZZpbQ`3H7 z>e|nN|14`-uw|L#X#LNPxcEyD71Wu+y~s>;f6EtCN)1gE13#mj!&i$QH7YaHY!)9fFVbhBS*n!GzFsDds2 zm?#Dbp%8i8>lNbD6kWz{XJ3Xr8sH!Xa^q#Gn}EB%@vXCkE5#P8vsA|#znbcNP*#dYZd z4Er2MmW-r{QhkxkQ5s8Vm1TrjaihDG}>{ugqB@=gE% literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/click/__pycache__/core.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/click/__pycache__/core.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e07bf2f69b5d456fa5b0e1169014901adf85ded GIT binary patch literal 89082 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 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/click/__pycache__/exceptions.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/click/__pycache__/exceptions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..30f90b37e2ea688d9ea3003a1d50556c0e5ff60a GIT binary patch literal 10211 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 Ga{dRM*(JmP literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/click/__pycache__/formatting.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/click/__pycache__/formatting.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e0fc86c3b371e558b32cec11cbf9de46ad1f3f66 GIT binary patch literal 9476 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 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/click/__pycache__/globals.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/click/__pycache__/globals.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..27809a19e3901b46db0505acc70bf22fc8c2bd08 GIT binary patch literal 2448 zcmZ`*UvC>l5WhX29mh%BCT(fb7FZ!X^u5XXs zJv)w4gxbFH9oon833%i)@OZC0^_jN{sm$!zkW^u%+uPlloBhpiXJ${Wt<^kezyEP# z@O;Vh{=~`g25a7z@R;AA;~po{>k@eT(jS+)CE^LPALxrtQtnoGi3f6NTTbnE;w z-{9w9bcSEy=h2E--SP^1I0AbY_#5!eSx$Dn#+xqyz1L}wyew772*m@RFq#EJuZ zE3cSXip0KLx1xDFwn8&`{}z)*{E%0)u$fMD0N;f8;iBOfpKW;lLMiulz2~I!96DWw zxkheX_ws%#Qe)BD&y0-|(b{DRAE<-YotceP(%Stoi#y5+(;CkvBAK*gJZPm(_DS=` z^_Brd*HRWfU?b28WgI?ejied?z-Btj&y9rbg_+jiK`$&^T0u}gbb+te;MM$J=(>t1 zm$7qr@yq{^>s6ehg|j%QLwCXwZh@a638n+xVa<9^2`ARyFL8g%d**)+v;>|FYNcgpSNji!f4sI*npj9mk`{g0s#@3~{W5vEX)`&@f`j zC{9K+wgxmJHi^OJfFUce@d*|S2AVZzW>3*HGtp@pS801JY}D@0bEauRm5Tmx#^*+w zO*#SW;3DH(@OGPi+Pq%aZ>LPNF)fmx} z-*kE|{a?I-cKFU7h6h3eKn%_jBH&~&b{b1Lv3U?OWAjSS)ttO+EM#zA|H@h&4>DVr z&ucpg7YA;ueD(Oo4c`@!oQTu1@dD=C26XQNo|L?pM+Jh5Gid6~= zluOc07+7zgJoPylL3%zd9eK|Pftn7LvUK>-9S8t{F`tO(g6~CyFLKYh($wd`RHqSW z#F1BfJsyX)*UM{gsB`M`3QJRw@CMPi?`xjqs~ByIT)74c2J6YDudl!>gy%#r-$G$IR8r{^3?sA>JPzK6FgOBO8PSy^D1H{W<)vT9Lnw7_b>oQa!@cBy z2Zz7zVDctR&a)oLhKlY$FCw_e1~qhxZhJbEYy>rBXE=}Ke-j4l57q(ufte>0%%JFC zQ4stpRltUxVhT7Fsni2hNF7x!*paTqQ7;Ot6Lj`8UJnqOcq8byi!r`VJ>CmYl9ZeX zU=j%H&7JuS)D5y+EkoG)Rlh>ulA^HCAh#fz+|^lusm8w#mv{}*1c8enjAJM0018y- zxVx*do>%NFg`%hNqRN+Tqy^(R$Fs@T_U_%e+1vi+=JvNcov*v=g>DZnf01CRGP!RB zWGvKqx8ppfA)vHWj5~kxV4#%DtKX$qznOGV>O#VyKQ)l5pN|#Kr1%1J&|p|sy;V~2 Ws|5R?R3|}jg3wU~|t(IzcfW7C7dydGeNvw*LA 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�ZJ}+U^l(Q+u7+%Om?BVa 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 Gmj4fv@nr-6 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/click/__pycache__/testing.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/click/__pycache__/testing.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8b9366748ea23e07cc6e2c709713e0a35f58f898 GIT binary patch literal 15206 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 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/click/__pycache__/types.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/click/__pycache__/types.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..92f76bfa9ec40221c6f2185eb4ac425aab1d9ba7 GIT binary patch literal 32892 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 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/click/__pycache__/utils.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/click/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dc602b9dc85a9319f5cdcd1c71315045c14416d7 GIT binary patch literal 17996 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 uXXfo0_e 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/src/myvenv/lib/python3.10/site-packages/click/_termui_impl.py b/src/myvenv/lib/python3.10/site-packages/click/_termui_impl.py new file mode 100644 index 0000000..4b979bc --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/click/_textwrap.py b/src/myvenv/lib/python3.10/site-packages/click/_textwrap.py new file mode 100644 index 0000000..b47dcbd --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/click/_unicodefun.py b/src/myvenv/lib/python3.10/site-packages/click/_unicodefun.py new file mode 100644 index 0000000..9cb30c3 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/click/_unicodefun.py @@ -0,0 +1,100 @@ +import codecs +import os +from gettext import gettext as _ + + +def _verify_python_env() -> None: + """Ensures that the environment is good for Unicode.""" + try: + from locale import getpreferredencoding + + fs_enc = codecs.lookup(getpreferredencoding()).name + except Exception: + fs_enc = "ascii" + + if fs_enc != "ascii": + return + + extra = [ + _( + "Click will abort further execution because Python was" + " configured to use ASCII as encoding for the environment." + " Consult https://click.palletsprojects.com/unicode-support/" + " for mitigation steps." + ) + ] + + if os.name == "posix": + import subprocess + + try: + rv = subprocess.Popen( + ["locale", "-a"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + encoding="ascii", + errors="replace", + ).communicate()[0] + except OSError: + rv = "" + + good_locales = set() + has_c_utf8 = False + + for line in rv.splitlines(): + locale = line.strip() + + if locale.lower().endswith((".utf-8", ".utf8")): + good_locales.add(locale) + + if locale.lower() in ("c.utf8", "c.utf-8"): + has_c_utf8 = True + + if not good_locales: + extra.append( + _( + "Additional information: on this system no suitable" + " UTF-8 locales were discovered. This most likely" + " requires resolving by reconfiguring the locale" + " system." + ) + ) + elif has_c_utf8: + extra.append( + _( + "This system supports the C.UTF-8 locale which is" + " recommended. You might be able to resolve your" + " issue by exporting the following environment" + " variables:" + ) + ) + extra.append(" export LC_ALL=C.UTF-8\n export LANG=C.UTF-8") + else: + extra.append( + _( + "This system lists some UTF-8 supporting locales" + " that you can pick from. The following suitable" + " locales were discovered: {locales}" + ).format(locales=", ".join(sorted(good_locales))) + ) + + bad_locale = None + + for env_locale in os.environ.get("LC_ALL"), os.environ.get("LANG"): + if env_locale and env_locale.lower().endswith((".utf-8", ".utf8")): + bad_locale = env_locale + + if env_locale is not None: + break + + if bad_locale is not None: + extra.append( + _( + "Click discovered that you exported a UTF-8 locale" + " but the locale system could not pick up from it" + " because it does not exist. The exported locale is" + " {locale!r} but it is not supported." + ).format(locale=bad_locale) + ) + + raise RuntimeError("\n\n".join(extra)) diff --git a/src/myvenv/lib/python3.10/site-packages/click/_winconsole.py b/src/myvenv/lib/python3.10/site-packages/click/_winconsole.py new file mode 100644 index 0000000..6b20df3 --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/click/core.py b/src/myvenv/lib/python3.10/site-packages/click/core.py new file mode 100644 index 0000000..6d8cace --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/click/core.py @@ -0,0 +1,2953 @@ +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 ._unicodefun import _verify_python_env +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 defaults for all options. If not set, + defaults to the value from a parent context. Overrides an + option's ``show_default`` argument. + + .. 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] = [] + + 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. + """ + # Verify that the environment is configured correctly, or reject + # further execution to avoid a broken script. + _verify_python_env() + + 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. + + .. versionchanged:: 2.0 + Added the `context_settings` parameter. + .. versionchanged:: 8.0 + Added repr showing the command name + .. versionchanged:: 7.1 + Added the `no_args_is_help` 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. + :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. + """ + + 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 [] + + # if a form feed (page break) is found in the help text, truncate help + # text to the content preceding the first form feed + if help and "\f" in help: + help = help.split("\f", 1)[0] + + 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. + """ + text = self.short_help or "" + + if not text and self.help: + text = make_default_short_help(self.help, limit) + + 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 or "" + + if self.deprecated: + text = _("(Deprecated) {text}").format(text=text) + + if text: + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(text) + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes all the options into the formatter if they exist.""" + opts = [] + for param in self.get_params(ctx): + rv = param.get_help_record(ctx) + if rv is not None: + opts.append(rv) + + if opts: + with formatter.section(_("Options")): + formatter.write_dl(opts) + + def format_epilog(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the epilog into the formatter if it exists.""" + if self.epilog: + formatter.write_paragraph() + with formatter.indentation(): + formatter.write_text(self.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 + 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 resultcallback(self, replace: bool = False) -> t.Callable[[F], F]: + import warnings + + warnings.warn( + "'resultcallback' has been renamed to 'result_callback'." + " The old name will be removed in Click 8.1.", + DeprecationWarning, + stacklevel=2, + ) + return self.result_callback(replace=replace) + + 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 None for regular groups, or an empty list + # for chained groups. + with ctx: + super().invoke(ctx) + return _process_result([] if self.chain else None) + 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 + + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], 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.0 + Added the :attr:`command_class` attribute. + """ + from .decorators import command + + if self.command_class is not None and "cls" not in kwargs: + kwargs["cls"] = self.command_class + + def decorator(f: t.Callable[..., t.Any]) -> Command: + cmd = command(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + return decorator + + def group( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], "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.0 + Added the :attr:`group_class` attribute. + """ + from .decorators import group + + if self.group_class is not None and "cls" not in kwargs: + 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(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + 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, + autocompletion: t.Optional[ + t.Callable[ + [Context, t.List[str], str], t.List[t.Union[t.Tuple[str, str], 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 + + if autocompletion is not None: + import warnings + + warnings.warn( + "'autocompletion' is renamed to 'shell_complete'. The old name is" + " deprecated and will be removed in Click 8.1. See the docs about" + " 'Parameter' for information about new behavior.", + DeprecationWarning, + stacklevel=2, + ) + + def shell_complete( + ctx: Context, param: "Parameter", incomplete: str + ) -> t.List["CompletionItem"]: + from click.shell_completion import CompletionItem + + out = [] + + for c in autocompletion(ctx, [], incomplete): # type: ignore + if isinstance(c, tuple): + c = CompletionItem(c[0], help=c[1]) + elif isinstance(c, str): + c = CompletionItem(c) + + if c.value.startswith(incomplete): + out.append(c) + + return out + + 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: controls if the default value should be shown on the + help page. Normally, defaults are not shown. If this + value is a string, it shows the string instead of the + value. This is particularly useful for dynamic options. + :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.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] = False, + 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: + 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: + 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'.") + + 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_is_str = isinstance(self.show_default, str) + + if show_default_is_str or ( + default_value is not None and (self.show_default or ctx.show_default) + ): + 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] + 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) + + return rv + + 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/src/myvenv/lib/python3.10/site-packages/click/decorators.py b/src/myvenv/lib/python3.10/site-packages/click/decorators.py new file mode 100644 index 0000000..7930a16 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/click/decorators.py @@ -0,0 +1,436 @@ +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 + + +def _make_command( + f: F, + name: t.Optional[str], + attrs: t.MutableMapping[str, t.Any], + cls: t.Type[Command], +) -> Command: + if isinstance(f, Command): + raise TypeError("Attempted to convert a callback into a command twice.") + + try: + params = f.__click_params__ # type: ignore + params.reverse() + del f.__click_params__ # type: ignore + except AttributeError: + params = [] + + help = attrs.get("help") + + if help is None: + help = inspect.getdoc(f) + else: + help = inspect.cleandoc(help) + + attrs["help"] = help + return cls( + name=name or f.__name__.lower().replace("_", "-"), + callback=f, + params=params, + **attrs, + ) + + +def command( + name: t.Optional[str] = None, + cls: t.Optional[t.Type[Command]] = None, + **attrs: t.Any, +) -> t.Callable[[F], 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. + + 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`. + """ + if cls is None: + cls = Command + + def decorator(f: t.Callable[..., t.Any]) -> Command: + cmd = _make_command(f, name, attrs, cls) # type: ignore + cmd.__doc__ = f.__doc__ + return cmd + + return decorator + + +def group(name: t.Optional[str] = None, **attrs: t.Any) -> 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`. + """ + attrs.setdefault("cls", Group) + 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", 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() + + if "help" in option_attrs: + option_attrs["help"] = inspect.cleandoc(option_attrs["help"]) + OptionClass = option_attrs.pop("cls", 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/src/myvenv/lib/python3.10/site-packages/click/exceptions.py b/src/myvenv/lib/python3.10/site-packages/click/exceptions.py new file mode 100644 index 0000000..9e20b3e --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/click/formatting.py b/src/myvenv/lib/python3.10/site-packages/click/formatting.py new file mode 100644 index 0000000..ddd2a2f --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/click/globals.py b/src/myvenv/lib/python3.10/site-packages/click/globals.py new file mode 100644 index 0000000..480058f --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/click/parser.py b/src/myvenv/lib/python3.10/site-packages/click/parser.py new file mode 100644 index 0000000..2d5a2ed --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/click/py.typed b/src/myvenv/lib/python3.10/site-packages/click/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/src/myvenv/lib/python3.10/site-packages/click/shell_completion.py b/src/myvenv/lib/python3.10/site-packages/click/shell_completion.py new file mode 100644 index 0000000..1e9df6f --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/click/shell_completion.py @@ -0,0 +1,581 @@ +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(value: str) -> bool: + """Check if the value looks like the start of an option.""" + if not value: + return False + + c = value[0] + # Allow "/" since that starts a path. + return not c.isalnum() and c != "/" + + +def _is_incomplete_option(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: + return False + + last_option = None + + for index, arg in enumerate(reversed(args)): + if index + 1 > param.nargs: + break + + if _start_of_option(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(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(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(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/src/myvenv/lib/python3.10/site-packages/click/termui.py b/src/myvenv/lib/python3.10/site-packages/click/termui.py new file mode 100644 index 0000000..07b5257 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/click/termui.py @@ -0,0 +1,806 @@ +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) + if value2: + 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 get_terminal_size() -> os.terminal_size: + """Returns the current size of the terminal as tuple in the form + ``(width, height)`` in columns and rows. + + .. deprecated:: 8.0 + Will be removed in Click 8.1. Use + :func:`shutil.get_terminal_size` instead. + """ + import shutil + import warnings + + warnings.warn( + "'click.get_terminal_size()' is deprecated and will be removed" + " in Click 8.1. Use 'shutil.get_terminal_size()' instead.", + DeprecationWarning, + stacklevel=2, + ) + return shutil.get_terminal_size() + + +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/src/myvenv/lib/python3.10/site-packages/click/testing.py b/src/myvenv/lib/python3.10/site-packages/click/testing.py new file mode 100644 index 0000000..e395c2e --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/click/types.py b/src/myvenv/lib/python3.10/site-packages/click/types.py new file mode 100644 index 0000000..550c6ff --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/click/types.py @@ -0,0 +1,1049 @@ +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] + return {"param_type": param_type, "name": self.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)!r}: {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 writable: The file or directory must be writable. + :param readable: The file or directory must be readable. + :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.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, + ): + self.exists = exists + self.file_okay = file_okay + self.dir_okay = dir_okay + self.writable = writable + self.readable = readable + 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!r} is a directory.").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.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, + ) + + 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/src/myvenv/lib/python3.10/site-packages/click/utils.py b/src/myvenv/lib/python3.10/site-packages/click/utils.py new file mode 100644 index 0000000..8dd3a00 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/click/utils.py @@ -0,0 +1,588 @@ +import os +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 get_os_args() -> t.Sequence[str]: + """Returns the argument part of ``sys.argv``, removing the first + value which is the name of the script. + + .. deprecated:: 8.0 + Will be removed in Click 8.1. Access ``sys.argv[1:]`` directly + instead. + """ + import warnings + + warnings.warn( + "'get_os_args' is deprecated and will be removed in Click 8.1." + " Access 'sys.argv[1:]' directly instead.", + DeprecationWarning, + stacklevel=2, + ) + return sys.argv[1:] + + +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: ModuleType = sys.modules["__main__"] +) -> 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 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 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. + + .. 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) + + matches = glob(arg, recursive=glob_recursive) + + if not matches: + out.append(arg) + else: + out.extend(matches) + + return out diff --git a/src/myvenv/lib/python3.10/site-packages/distutils-precedence.pth b/src/myvenv/lib/python3.10/site-packages/distutils-precedence.pth new file mode 100644 index 0000000..6de4198 --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/flask/__init__.py b/src/myvenv/lib/python3.10/site-packages/flask/__init__.py new file mode 100644 index 0000000..feb5334 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/flask/__init__.py @@ -0,0 +1,46 @@ +from markupsafe import escape +from markupsafe import Markup +from werkzeug.exceptions import abort as abort +from werkzeug.utils import redirect as redirect + +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 _app_ctx_stack as _app_ctx_stack +from .globals import _request_ctx_stack as _request_ctx_stack +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 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 safe_join as safe_join +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 + +__version__ = "2.0.3" diff --git a/src/myvenv/lib/python3.10/site-packages/flask/__main__.py b/src/myvenv/lib/python3.10/site-packages/flask/__main__.py new file mode 100644 index 0000000..4e28416 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/flask/__main__.py @@ -0,0 +1,3 @@ +from .cli import main + +main() diff --git a/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/__init__.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a7e13b1bc8ee3e3710abaf6d095e72cdb56bd77f GIT binary patch literal 1894 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%0AQat7{4ebG2BU2M#U_XyL+R2J2 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 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/blueprints.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/blueprints.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d45e379a253e38e759412cdf9dbb2b133c020205 GIT binary patch literal 21629 zcmd^nYj7Obm0ovG&wBvkMGyoju|<)BV39*o56cVFvMEZGwNk+fNv*tN$%DakgB)lu z19lJim<(d?f*WF!*z1jxY&I?>V6wXjla!OHRHgDOmB0CuA4yey^q(ZH ziI=b7@uqc6vo%|9Y8CZguNZhYnyEFjV(KhQHPdUEN(On;PB*h_xk^s*8RYYoyyUaU z7b*qG=bHLju~L+L9{EzGB>4jJBb5=!7m**Wj7q+Q{JzRQ$&VmERvDB0DDvZ#amnvP zexfoV`7z`tE0dBRM}Dd@rE89{y5GHq8BR2(*A7$;NbMwQXDTyNd(fV`qNCNp72}{* znSD*O_uEsqHG68ys2sxEw0!_?2b{uIs&d%YFKP2LKPJW&=XJkmJ1ez~X2)*SJ9r)4 zShs5(r+UM!t*<-okAXrB#WPi>Wv{mztxk2tZLd|YH=G;Qm5o*%b@{62v^tHJ)5J^e zQoXja(r((wPn}!oIPOK~+J@tG&exjF+H%uD`RvQiO51fVG+eJUSi4`<4pxj^c51HO zzR^m6vMxJo>rG7fe7n_gZg$>s+jYnD+HTn9p6*YFZ7wvLn9s19*P89+S~F2I752H@ zKlO>XFTVMTLRi=u3p$L_->5Y=oVQ$OefJDdpT5wndG8}L^{VT(-LKYKb~B!cKlw7c zuDd|)C8x8oeyM}?)JdP@r-+xY;PGrEj#kla4cx3(Qnq2I$h~&PF;~-e*2&m8JHJw} z3wH6gS;^+{vB&L_le0(ABJbo5YWAq)%+&(&s-Nn!&mOy-t`zM&cx1vofT6lSAu8H# z&Anw^1zjE2YA>%k^^OG^TCQ`Y;Q^_Q))lK}Er;u{ZZtYqtaIJMfb!?eKr)_}&qxo8Oye-%2?^|SI&de)IJ3k*S!p}#8 z`6;Zy-4As5+4j0L_a|1!zg2|+S61g|T+GL9E!NX$8h*0KWbmBFRb$7r^}G6Jx|g=K4b7cJnZBClJ6hn876w{mdKqc)jI_w`9WC%ki&Rfv z&EDlW*`Nd*BJa6QUV0R^IDQfN;!Y`Old;j~t`7O4f&RHgKkscU+wHYlqvaPi+-7y% zbygZTeX~_tbNnLHut@VuY!C<&@18b4;?82N?hKPdOb#RQQ&*gh`#4{ZFtM0Cfy6f{ zfc!}Uxz4TRMX=l_S)WmYX+G}sR?6DA2nz7?%{~9;{9F@ z!T6@T(RBP=C~y6IBx~zD*}@Mwik$TZ9`A=pKtr5$8@hY2r@Pa(u><<9YCDDviuUv! z$cel93OPq_k<+wIy=Q{kmSN|jZyW~=BwXj+wC$E-%pxJyMk^jaIv=7o4GmWuRE09mUbOYnD7r2WjP^SCO z&RJKTCJvc!<6@77@&v+!Xt18z~68}=58iH&H}&dZ*qj6q+Bn_Z&jGD<=`Qo7VO zI$-7wWD#L0W`?lo6IKKkQFzX?$mB{iux9Z?{gkkop9@*t*UR&x!p*+9iW3q-!0Wh; zbwATo{|gXOL1V?C6b{1F?o-J5srB}{>=nOMv+XK(0M{^J#+_%E6HHDrDKini zKh0dk?e6FJ`XZ9I@OT7YD4P1?dd3(9FM=EKOykYa59@|*er%Y=&y959qpmfKCzI2e zHx?J?OJsN1_Eo=7t**6gOtf0{OV#SNjaoCP$yTd&yN+VLe zi=me6Is0jhb_ji62i~}1VrC4vN#`&W*2Baa)-i8?4(%S3cF#D6lWk=lC+w4`e|#vM zBY<-xfK#?lp`8`LIWhp}w0#EkPYi`~6mX6PaGtfFL%SyfI7bKIJa4~%`eXJp&T*{f zI9Bj^`$b^tDU{5iWDX@?uzw9DPorcWCG#j*u)m0s&!OZQlstoyv-X!zasnkMQF0O` zFWFy4N!k7ia74~H<(xjKIcGR8v;f}F=A8X9+B}P1&!Ox&l$^I;LCNzdc>yIapyXBi z0!luAM>Dm`ix9TI?j8is*M5}Ow2RO*9V+Y)hq0hLftPx_*@RvPU5I*_+up#jD9ThD zlGP10xs$F#<;sp^um{0g>p-DuS<6l&z|jD3YIv_TlTum0h;~*kNd8Z%^ZJ%+18;qA0ttlzU1L_3W%P|@X=PFTwr4D)i(h$m0WAx@wY*IFT}LZz45tV@tK zmw?7=(opHBN&PWE$t!AjrBjFcsXC<+Bnxz9l2NANCTJov5Cl@E1`<&xr`)c!Lo$j0J?Y_<65A2 zVPU=I*4E_6U9c__sicNn5}cS#%GNs#sPbSoaPm6Ncgz9Dzf-GUl?n5lj!ymf_zr+K zc$w+QA@+bVaCH!!?*zC52V3)21bJyGJOP)M%9tc@K`q9!nr&Qh9KqDmlG|=~s_V7R z)g`syki9s!2#-pw2gE&=0u?6cEjyZ12I4R?MMW@S<2q*Djuwci_Vwmcq(eE@5kin^LNyT6Zg{-i ztIL+G@)p^WmW5%BgP!j1u(b#TojqtzYT!IkwygePjIeZ$4w6gusV>h5y35JWeGgTiZ8|w`v8?Sw|+Gs+vVXD=j@}^ zL`(@NLn$7DhP+9T8|)T=2+5sbleiNp07(UD&U<-;PRs%41|+u^Po<&6jUq@4LG6b= z48~OCh7qO)Is&OcCc(}f5Fc0|%r#z2NVKCZf#_HxALE`#>jpTFMUZq}Cj_GAq>jeE znMC(wP9%Ea>c9b!RU|l5g|8s^Kp>ovLog^P4depX7+}^Ta9)!+ouJH8m*wFjMWm4t ziFEFDNQjVB$$=t~wP3v*wNQH_UV#AWzeeG96OALroaGvfE?n8tQbO3u25nh&$L+wJ zVBuoDA)=q`-S8p^5p2v6Rxr^tv|#*u!xT zvzKk1fAe+dO=}p^4h%??ecW);wJIF}Kn^x6$VKZ`$89&c?Edpjjj@5_OzBz##5PMy zVs-$KV4#8Zh(N$4*ATmMcPw|}Fj!=fG}x!R@KE=uEV@V{}VhOZ^)Su1J`)x?zc?%6V-+n*lelLdsiL%-*G?#NhxU34 zCu|*_9%C)FDYmT+EL~grmJT}?>|HyV9;~eNqu_Fs?*6BXff<|1bfj?a)}M#z!IA8U z*H6jEeVe#@!0IiEVg!1ZR*vQoAnr?a<}rI^V-5E-=9O7F*6sqE_<#vKf}%{}vF7BG zws1h0q+xgEGUgZYsC9#*HE~n3c~4OWeUad>(DRmq*}`gzWATcmNRP@^`-Z5Jp2H0U zaq1~`iP{!al^fQ^dU(UP8ehrDA( z!XiZOr-7aKsDF>VH-@B?De18Ja0`55elnKrj>XKbnhr1wt#4!+v5wh#2Lg%K6tTI$ zNPfFS)8~%fF?zbz0sA^eHk-R118!TQE=t7dP%FaFEh&BMQglL-PdHYS8^4~Rlf)CH!u%vh3?mxkivc31W$3m zP2XTnxT&Z}DB%7pN<9o+4AY~nP?7dMFGFGMAZj+qw=2!WpNvYxl8ONN^A>{JdG>UN$5k+ zXk(8G!HE5ZTolb@m+gnv37!L3VPL9bYZ}q|rW1DuGxb{u*I*%Nti#nqdBsBnmWhp4 z12F?KdVDkBd}v=&mv`iFqZo#kP#XqPqB(SrpRctj*rMH#G^7FBjSiiPi;x(vgK=E4 zkoyjjP=v%@%w6m|5kic0zWeAW;wv|j)2I5hn!(0(3aaokg$(5$%RB>V&)5O)!gFVA zrX-)*)>n1BnY|SJZ1By&&z6FZ4<5PS)gW~B)f9B=H+$x`_I}EJ%1&=rlT9N5wY%gbUD#vV>s6w}&+UL7KaSaRbdX{mHBF2TOfP>PJ3E(<$*C=u@5S9eqWI z^I-gTjxcv}cePg_@VE4mwwVp)p>O84q1|)Dvzk4ztylBg`c6T_VfJon6K|_U_glUE zY6&^|4JSV^kQ=3A<2xy6YFTfqmvjG{9L;oW;P$mVEo6t$DR z5!C+k9><%)J0fW?AHMC!+y3Zn8gJ9l+X1{Ch~8%KHWR(UE4zA-Z-6n2*=IKQ_4f7h zJS4CEL})vUnnR%N82%q#ee8R>`%G_)YeQ}ydZTRTaaBj@)jHf8>l~3WvRDE0)_?sC*Wff>Ao^^R{&^d@$W-qqy4W*>roc(OMcjC#H|zWOBI^Q%vyM8`b7 zDRnA`(w$>AMzRkd(0Y^LLgbN~un(QpTKl7xS9_B|Sup|0V_ubmU!bj@)q3MQ$H5&F zcY&qv>DS735%T%5+Pe_y=amf`riyK7eg)R(Ri^Oqn$cjMW{kj-;%Rg#9sp@(`eMd41~dztu!$Ubv(zi zl}D39Ej>g_!YD%NDZ+X;;2@l3Aw0^WdxuA93!Rjsz8|D|?b5v4TfCu@;p< zC0Y$g1-&?4Nkor^%d0z$FR^W(Q{pFi5aEuBJ322=37CT4@Q4bIH=am+iwkT!Fx|y4 z#JaD-grc^Owy?|p{~pD$p>0q@xtNF?iwF`?Dx$XN5{givrV!zu6jxdUINzpUlO7lq z049poGHyb+1VN*PJ`2?Wb{}C_>si?SA}}h@;wa8s*J2`eBg2~eP@n4-NIlVl=DKI* zsQe7MC{rteJ!z2Nx^rdgZQPK>2KA*miY9~yUZ-YVODZ{Kxt=d}Klh*!L>G?`)cx8c zf>wLt;pq4=RcBZT3Q*?j?>C+6PP6Z#$4egdlIQSvREK^GSDW{;h$7Orp=JLDtVh?3 z=&C38cG!%J^684Pyzc%vbcl^ue*Wwgr{&yScV9XO@#M<0X^HC`W$NFVBtm+;692=Q9l zd!tw& zvR5YV^=zQ-+J&>k3HIaqOYd@_a=+IKdghbvnFlR1?pBVoxM4bpq0M^Rb}B`tLGWNa zJrxr5K3ac+!_u^w(K2T4;|xp-7`)H8pln|WmW$>rmR)5NKgE%sa*yMmA|ox2l|r;N zJ#~k8oAqMqO4VAo+^c*QYuGp0eEez+me8cnS4BX*!pbqkXV_6Kc)T(p0;~#48zYCS zbb1H|Ty9GVBdd%?ae`ux_NSI5${LngiN6+0wdYUP7?ZuLaJmyjR_`j`pKw0KmTvz5 zi-nUJ{TT&3d;X!whd?ts7!>tEJhmrxK4l+I!GGZALbr+gG?zejs1zA+7L>~!%m-!H zZz;4thZcS=R0!s$b{iL-V11s~IC1V*iq1{(pYu{{+O6|`G9po%F+ z`YOaqB|Fo-LfC0pvI@ZC?vM~b@d8vP=n;XVu-$|UUb#lZJ^`*+uLc@cWdwO~w}{_a zIP{*OI7q_#Xp(YoAi>uKH1BUAQ<@#c1+rkw=%cW4=3wQ_z{;7+n20Q8-Y_#CJ)SF| zMMfWmx!=?aI^yH>%*VNG$(TsbB9Ax3pqf87@0aouMhTEcQD*Y*{-`;Meg&g|Ql=OS zqm03MfO3qXAWs`JM(&eBssL*o>Ji0i{%O*w5Rzn9e4>9aIP0pBPcKA8UwAYrpT$$e z<6T6ut+@pohYBvT1zKl$Dcv^R*$z?|@eOwtwdSgU`dQSQ%CxhSx})9E?-+Mdcg&SE z!{Kk|D6j1-L|m@B^JcSMvln}}RkVP06X|3_IkfpUw#}#CV z`FD?qS(%tjQReh5&Qo?B*YSPMi8k9(F{gv$b<>#8bDwmlhtH=^yWqiV;^F_F9!8@4 z3LQi@k}DCvi4bVmpXFSo6VQ7;=msNcgn4;8q62Id z{)SapG}qw{TTQ_R3Kmw5Fq~#+3O!*0U?yn-# zT}ZIPZsA2hG2ab{F8BK!|F1C-=&^|U>nQt=5yy={L>+m^Fb@?_k3X2}uE>{(Kf8!h zaE5bTEQEeJ3=_`z|B{#*)aKNL_7qh2$uuIU_R`=KfS6^X&F1bSmkbkC{aTv>@ZUMm zAE3vc8k=hOP*K(Rl`>7Auu?M`&N#o2xC#MAIQ*pxEH%Oj>zBoUzqrWCs;N9gXpKYP zQbOxN8kYhU^WditTQvWe9OMtldk@m8)F6FAi^^ac52f=@RZ!NBCSG(z0VuP`HgwVX zRQGoV%_99~Lwv0Q(LwN7CITa2-f(U@b$mZ84t!C)3Nm7*3K%Ivts5d^plBbv^{Ae?CqNRz&4!ZP=XnM!>3 zyFA!@Pa?V>00zjlwI{j4A0rUV4<}l5Uk`}~zbEWgLGU4e%pjy(7&``xgx_I%0I|qr zR6NCaqHaAq2%U_Hl#<&{Wj0uF-&B=Z`oUy74lJsOFs=K1e0V4D*9UTtc0Xf1kP4t+^z)X;E#O&4Kp|tzMLE81%;`fr*yLMkh#l$YO1kl4bAFtWVk%ujU zwCDD7|29#U)au$Sc=$#;3GBIl2W`72V|uC8K5&=qO{npK-cNIkzsE6>R|xTLB*u6s zS^nuDS$2Cv9!!}CjgjRmNtqiGH4gU*<1+Z;H4mjy1n;v`YyHuv^8A4S=RnvjywRC{1AlmX|F zSL&7wNQ3wr9FWwXO5ylS9s&;^l75{ng8Tbt z+Tq+WCO=@p`>k7G@^_i!nfwtGY6tEgGhsl0`zK7eeciv0#5XVBT6g?>B!B%Bel^ei zhpcDty!(%sQ1ZI}7>Pd;e1o#?G@IeKC`B^9$tEJL4kAZA$%BtkeqP9Y9-$GYnZnNu zN%%yVnm-GFc4!JeE|kNM3*|D#hqQq-Dm67>jGCW_ z#G%v?$y2yLlb;^fzGdVH)BGs;V?~5#0-ljA{F!kWK_2LVpp5&*xProWBY2PMCU@20 zeXqKS2_qlQVj@40N4!S>@mSH|w@3y0Y+imSX8tkvheThdb88)Xt1yj^@T&0lVLS;t z^7Eqc;-{TF`MOml=LNt0=u%`Vrpq!XG!+sH#f7j!Q{fh23Skr>9O>wfT>j0sUag-0 z>Z|A9czyA;#P_af%@B^P?0+Tr4zB!Q$%P>HLa`@_s!j%>wj`vspF695v+5-fTl30D Xa#{{?E%-xh%<#XA)PSC;ski?(2)`=& literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/cli.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/cli.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7bffd19a86804513df676c36a074103515852525 GIT binary patch literal 27289 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 I7cO4-A2y8Q1^@s6 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/ctx.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/ctx.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..60ebd8881ec9429e500533c35bc7f14812327562 GIT binary patch literal 15568 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 N&y*`=yIfkh@ITnh36}r> literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/debughelpers.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/debughelpers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a4443e99024276cac626089a069a873160c884d GIT binary patch literal 6500 zcmb7I-ESP%b)T=Do&6w1Q4%G8#JN^dNJOorY@7K}vPAh&!F#dzTz? zc4m3+T~QqDrcNjz>O+A5L7oHxR33^N=u?qDAb&w0`Z%wB@_Sw)6m@^+&hCkt3+X6Nc9%ldD6IeAs^atpWmcRaYo?Zj%AzjoWfyOX$m zukG0uce$5T`hMFt3#k^>s z<_u~Yyos77-re>BpX2k7toB)cMmXDxJ%=ywvyZ&?Ild@-eumpUkDue`QFESOl`|{70!~D(ef@5n2n$1odE23^J+Xbd&WmS!cM0v!PKmV>7ht#Azh= z8IN?-GR@YOy&?$1H0p~mEb3v{&-gH*ax)Bfhfy;5QVm0%b;IxrOE$3?^LX};D_dB} z%JxuUYO%5rrM#0pT=`^QZ)NGq#_lj)%d}7{{rv|beXx?mot1(4_IB&d>nkeO;@SXm zi#E}wM?zlVqBGpw63IYF)f()}D&`_}Qyw0H71*ZcYl3$0^%gZ_c$^kAccBX&_jm=r z74Adu)nf5B&GSK=2=$TJFNOZwiO_p8>qDOAY+F5Q!uSw}zRAquHc@IZc5h3tn2U(T zis`LLvsklklp2{1WcC2xSakY~`a&sem71rFWQGQtA{8?3vgs;Tei-rf$=qhFu8SQ_ zFCPUmulI4QHXb8;+d8sG&Qp8ra{NAVxPv_ShS_@-Mh|Sn1HsfNjr#b}8J{TP~wAV!(z((sA*2wy- zI<_@V>cIXx%eHm_fg9Erwm}(Kt^C3%oYwWiet2wGat>XK+6_{UhXZ+&(Qsq{&gV;3 z-uk-kw!$z@V;zRA8%frU5_PjR>zv=M*GXABGTT$Yi>YK!NT$RSbEstPicSb3+KUuZ z!%iu^RaRKbe&Nx^i|VG(368P|rpH)#+gY3zel!?}loxJaZBlC`l3r1r=ttr1i2Zhx zMhN?n?rsTHxSe6IsF+!w-#<{P+|&iy{>ykY?ZELI|9`!&yx_d;*$)0t{%XO?U->ga zIdw#ITyz@~B6}KH+c*$;2E}DtzEb|Yil67#0|ZoBhT#=_Q*_e4oxl9TX-%`WWnTs~ zOpP9dVX{Gw*XePY9y1&*OLXXR9uIOBin<1tX9r$$(bRTPaq6Na+`?@X?Zub}Gp-aD zKY+k*!)VsCA$f>(!D9)ZlmDkVW$~~p24t{gd9w67oqc9}9;v$lJqE7;yz3FlaiP&$ zvB=<)oQwwW87cK%0&ftO>=-<9#wdiFw&F)wDr-pcIeLP>QvIzqhJIo za#S1P%Tb*-pW06yAS?(OBT$GNTbkcKQ~UPCp2H_GbR&4C0Le&B@_?rLIwFzpRl97tjuAxD2wO2Ij(QQ=~T^-n;h+>n5>r0J9~V-4g7S+9O30 zM;%Ou4)lrE1>GfR1fhzI_iE*D*Xu-HRwwS_q?KeTI!{dHl!Zuws=PAPy=&iJZnV$J z(h9Rn#DfwIq}){L(mz`S%o7MW$&8N{JjVnHF$TFvw+3 z8ld_X)w!5NejB9|xMCoM0Ow8Ih8y{IeFCAcRtZ1>pFW4~ zH{;riAniMt`!8vJvPXinW<^rnDOe`kC7X3|t5rN6!(O-Te?|cCE9+M_NW9IRM*(*p zTLiT!E_fvlJd^K(2?Bo;0`Q zcUfl}kVa_N#evL_%}_wXs1ov^#)j$5=nRyG%~-+-cp@X74Q{|~I>E6;OfU;OJ$2Fk z=`#Lq3hE~%fY_njV=K~#Ikv(HUkMGN3C(gi7}zlrfUINY{B_%L~7>wEGwsdH|gKC78_E`MI-a?@ipNS2V&9 z)BwD`j{qW=l3KZhDU1_ac1w+Y4HbngzHr)pmT)Xjk`ABngDZI5z-=NY$DYSu9qQV2 zg3q1*$yfh>dx!4MR)u)ydG)2a%BkO)l?(&(OVO>M z=@(Fla_AZ&d~q6PRE+>vnfxxcP}t$AJx+l^(H;pN4W$lBO0A)Y$E3RCa86N=;U*A} z!&MY6xR^YPZqK9QdDLyvm?T8!^GjC#-H;FagD}Y=E+nXDFFUrO8Jm7)ujU?O*I4eX zvgI>{N3lXl@rbb%zCsu-IEBttC1RrAX=Nn~A_jU1zN5tOd_Gj|+}Yva1EjB474s=duo+O9%5oN*()VCn->LGGizh8e5o zJL1&C3R-x&KB^tq;|4fcV^rm}i%1AP@pxm@fFc@ZrkkU{%vc{csTFUIn$u`^_opMM z_Rx|$d~Q6K&hvS^*Iu#)yZj913J%@z+{oj#?^zT3CW-m+f7lr*-`8lv5xlg{c)JO`?^C~N^ zJU|F;;<~)r%diqK+TaH45AAQ}#tow3wVUjN{E8toM6JO8rYq{2Fr3l^VD@H!*1i13 zr%1$MfYphkMc$#D8nKE2L}JF}tmJ@Cjo8XRF4^yF3ZkS*mhGU^aKKEW2dNm4&H;i~ z^4Sns2eM2zkyIdR4t6;chJmO22gF_Xu|i56@R*ythDp+49kYqRB&f5DH@9#IaB)Ju zo4>=@h7fE^>w#KbDHC3;0W4o=h3o@S5Y_5t{gv6AYUMlAAyr}5mlq`2V&Up+U_4Aw zn>8(JA|3WYUqN9BUnJpL(TMw$7c}WTNtvUhZPLXgI7U8+YKcEkzp@ZTl>#L+Uv-GBvG7((}fs-hDL<5^V`60LdxJ}r|B%>7hjwJfal>^M>~3gjiMJN5)1?O>gXxk7>s=Csf*k zcc>BJh!%T4OBGU)k`0F10Kmx^z=B~t2>g3&ngM3-yu&Ud2}}|XFSE^IBu(;9(Nepx z)-o|GQQb_k4pL^uwB#E!PV;0k-Xxsmb<`UMYeJWjlGW}~@;1_$G*)EP p#;ogwTMTZLnf03#mm4NS>Fg%-54XMOF8T|v1Z-hx@$CHd{{wo8>{S2& literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/globals.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/globals.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..952a741bfe8dc27a759343d0bcb843661545d692 GIT binary patch literal 1804 zcmcIl%WvaE829AqIFG*4=PocDkchM-EL&_`s%p~}!W^uLXOg%bd%WXuo23^@;i{{7PmN&mP=qS$x>K$%LH|0SqZCdHRmh9*W4Ph1Uawkk9d{Wq#ZWg23V`S zE}gLHHgn#Vt+4I3bG{)v;hMV!yyLF(rn|vgy#1r)Zt@OagMEvy^9|U$qIPY$+d174 zRnfgB?k?XHdwlEA0=Xm+I_wa+U`oblWPz7E@*d_+AY49Yaj4^(C!^Vc0;Ro z@CtIZPI@G($4r}mNno9?l+Wa;RN=*`QLDiV*!bW`+88I_`$2pq@2{rRL z0044ML%|}Dr_9i~N+~l&gs~Bv8b#AY&~Y012BI+;n0etB3Bd(-SVS3^E(Lvhc6NFj zsZZ&Vijq_sa2Av+KMh4>7@k4l&j3=yI9A#TBA{VmVk1CJr|Jp=vr82K0z?{XHIgFi zvv;8~|B@h!V+pC`$NvvW0+;|Qr^n0}^eQmZJS#ud8j_;-gR9ZG@C|s=M1|nX=6!mm zK#-Th!Big6L>QXJ6btuH)Wzvw=)>}ssl4BVdJcuasLq?UgwoMaX#o*eRqXpXKDSQ^ zm@=#*Sg$D%W1W-l$pXH&)Y45;GUaRX12L5aSy;z}dev;xTMmuqo0*s3RAyzP z;;i*7jZ6@VW383Wx^K7%t-UarWc7)FUK@Q=$|?~Hg>FOK8%uA&_Q!XFDU@b#p5h3I z!H`9Kq-KNDxtXeHFno~)Ckp0c5Y8_}bUBd0Xb|VNkNb~593+7eAH;x$O~7Z2-^XB5 zd=>q84zQ(C7io;JyrLOzL(tbYkQ%Y!=McRO!hhCC_yT z-s04|;CBa3?}3<=AzY6X+P@)cc;g`An872Aa#x%h(GTz_xVEjVxg2ox%j(N<&7+05*3&qX8vhk!?Xz!B zkG-R($46g&aq>hTpdklPhSAGU&g^BpqzGtVX}~0OlB3aU_y*>jcQ!9+kwy!3d2O(e z*_!9EC{o2Wlz5(g3+*@``W+;9Rm!=%dG=wbcq+vw*p~#$vp|n*T_2AAte~J)}IIEzW^Y;?0EnH literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/helpers.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/helpers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..771ec27e6d5e4b521dc58ef6211881941f90bb78 GIT binary patch literal 27442 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 Lq5I269<}}-<8Gi# literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/logging.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/logging.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f07742e71a951751657755d41c1eec484a7ef223 GIT binary patch literal 2465 zcmZuz-EJF26rNeHe-k%NNUN42H2hSprC_(J;KGU`M4Ge}QK*yv!c~>Z=KZZH3HYK zzuoTsULoWUoSeOiF!>m6{WA=L2pW-2_Deg|&YeyHex1l27CS{sL_xSwX;|)*DUpRi zMZE(n#i%;0b!xCu6eU=l2^>)tmFMm=+L;wqNd|RTzYw^hCT5k-$xX-P>lRA8N_QaC@Gf=%zLT3_Pz{vr!=IBpEY5iG#2=RuX55CHpaJ z`%trPdl0-A#=Yj2P3}IAMI;pjN4FuLuzemI*xg3MZA>3Bo0gDOWV1(m4jYU$L}Ni1 zNd|R_&^M>M+fo_qV1xNQzF}B693=`iz^Ecr(l^m0+Z^5lAb|w15*7lU+PZn3JTUE6 zE5IXbPP0d3b~0pkvZN3K#PM+E3~CKmxp0PQS;l*zO5(Htn5Cr*v=>An@$K-}qgFo| z%GO}4O&H787G&K`4q6WTuY2Loo(xH(bjJUtc zdthTzZB0`hP11$)>DG~7NVLV8n#B}LXfKtIY@J^C9`i52t=C~VBFE%}`~bgS(<7?h zG4wkU05yg4ymCYb&Rz11KBMZg0FuJIpx>$z;o4^xJ#+lqdS~h#qtW9k;&}1b)z;g&-^>+|~H(~e|YJXh8S_b5MvP-`plss_+v}S{DzJS)Y z+clijY2Hf9c}401cxHz^15asnxhG?JFj6b;VqApS`Q{2ae8122jt#Jrdp4IN6cWAC zJayS#Zxqw{bLpoA9#7Ir?x)i#ssZnT8l1z<%l=s5JWI%?X0w_uWB zFT+rAUFtels7p(ZLtVG@xBI7CRafEF;YW|I-{cyw9?FJ(%&y6F+Cy!=Y#_2WKd8G0KKbWJT8JRmQavQ`3PvI zufbZyRB`19<(TqcfX(+Lw!36jb5R6=BpF*!8cxLmI0)(xuvkhVMJ{LC;FsHCK^gzL zC`yuPT*yVD&5coQ4}v!{f!VR<%b94{otwCV9J8eTvJafiy`G-660$q)dDss!=G{n& zC8qNN@?v<6Av&jcl%6EfiA$V|HmIsvI|+u@Z4 zE87KiA3mB!?qq0uh%`ifoUP9~v$W#Wpbyl0u+X@qu3-%L#{%MMCL<^?rKWRXU#i_h zIqt!?0yTg*JFEBCRzH2Pc`r)^8zC)i!?)(aXSpCx3+^UK zl+{#!4Q++uklQX6Ra!lLv`L;R&VFiag_Y&3Ay-i9_1iF1NQG7?6zG(oNT;ws P7iVjiTv&7exl;TWtl7eU literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/scaffold.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/scaffold.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2240b8f3983515f8849b7ceb39427fb45356e088 GIT binary patch literal 24768 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 sS^XPPx# literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/sessions.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/sessions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..76f092e75eb349c4825e63a5d4491cd066cd6618 GIT binary patch literal 13617 zcmb7L%X1sadB+R}4}#!Z@73Dl^*R#Q66no3DHr{SWSX*=T~V^g^=4rwzz{tohXgR# zo`EPLP~uoynoBBGsgw`7B*z@*>XUD&+DpnwdGq^q&kP12xUol? z#!Pol_t)S1`?~4R%~f)^e)*qo@9ljvm-`i8vR45wcW?*)g+k zui3Ubg?hnYTfSZF6zfIxY_&_Ba=omc3wWNX OyV9Ah&*Hfx%I#`ru0E%pXWH|f zh5CY#bIqeg`L3E_slJR}mG(;KLj8j3HQT<}xm3T@xm>?&|O{VHk}#S&_k+^gtu4e!fh1@9}*&H8KZ!t-4HI_fTni>SNkzJ@-p z3u7m@dg<3#b#8mrh~^*kLuaq;K5%+HuX})+vT#B-^g1q{tKW9Sj(5;?!oKADrS~7d zx8v-)yJ!|WuJoL?H*h6;ZaD4sp3^%1j@Jr*ZD4d%7QCS0_3&_E*Eu+F#h>mx+#dU? zaIftI$E#*kdhCAGcY`o0KX!wj-woUrAaKJcD;-N8GXPkT;R1h!-E zIf2)*1y+MrN1oazUU+B+y0`6wq4f6pp&QhqqI7|tZi|afEr~?%K{reQ(#4SPYHxpKE$~A3b`L~!4$xm5 zyF`U2PP^}Jx7aPY_?*YB@Un=9FgG-w8$;mc8xS$z#@v<*sK@%OJ>PGynsOPh@)8R! zQ5P5ZbP>gM+zOCI^WN_2Y*cPEx=zP!G=Qx}#~1xJpR0|=M}4Oqx0D(U;kQs-?nxi; zhNqJ2QR79$zzsuJM)|IL5|uH6x9_Z# z7*^3LlnavWE!<;QDSiunhKDRe3$qTEt`{KOmS$y<-?x5}+c!i}ls=vV6PMi?FgVye zuAdQ=kE>wnMb$DJ3jo`T>N_fux%%w6?Nlst_3BT+wDmbqVJTYKaa$1j4c|ZZ+?c`+ zbX@M+PT<-t@J3+o`!bP;fCA$R+wa-|6b7DJ>dT;3so1y_zbDc|J>hl*M5^7!0HNaX zb;{IwGr@S%2Jfm*I2vggGCOfr5iQ(;⋘sdZAXof%nYFe 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 bQ&o+k$(luDF~59$@vZr#++P=ea3TMHM$@3q literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/signals.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/signals.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..067acbce0d6584cf50b57926f74fec83510ebe63 GIT binary patch literal 2404 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 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/testing.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/testing.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b2b86e0f7a17db32b0cc66ef42e2c84d8864ed58 GIT binary patch literal 9390 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 Rboy1+)#Z1kKVJXs{{@x!`C9-0 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/typing.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/typing.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a547cd1fd14d9ae2f8e8295955d1eac66d378fb9 GIT binary patch literal 1428 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 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/wrappers.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/flask/__pycache__/wrappers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f5b6ca9bb80950f69f19d46bb4894c2009d3c5fe GIT binary patch literal 5045 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 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/flask/app.py b/src/myvenv/lib/python3.10/site-packages/flask/app.py new file mode 100644 index 0000000..23b99e2 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/flask/app.py @@ -0,0 +1,2091 @@ +import functools +import inspect +import logging +import os +import sys +import typing as t +import weakref +from datetime import timedelta +from itertools import chain +from threading import Lock +from types import TracebackType + +from werkzeug.datastructures import Headers +from werkzeug.datastructures import ImmutableDict +from werkzeug.exceptions import BadRequest +from werkzeug.exceptions import BadRequestKeyError +from werkzeug.exceptions import HTTPException +from werkzeug.exceptions import InternalServerError +from werkzeug.local import ContextVar +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.wrappers import Response as BaseResponse + +from . import cli +from . import json +from .config import Config +from .config import ConfigAttribute +from .ctx import _AppCtxGlobals +from .ctx import AppContext +from .ctx import RequestContext +from .globals import _request_ctx_stack +from .globals import g +from .globals import request +from .globals import session +from .helpers import _split_blueprint_path +from .helpers import get_debug_flag +from .helpers import get_env +from .helpers import get_flashed_messages +from .helpers import get_load_dotenv +from .helpers import locked_cached_property +from .helpers import url_for +from .json import jsonify +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 .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 .typing import BeforeFirstRequestCallable +from .typing import ResponseReturnValue +from .typing import TeardownCallable +from .typing import TemplateFilterCallable +from .typing import TemplateGlobalCallable +from .typing import TemplateTestCallable +from .wrappers import Request +from .wrappers import Response + +if t.TYPE_CHECKING: + import typing_extensions as te + from .blueprints import Blueprint + from .testing import FlaskClient + from .testing import FlaskCliRunner + from .typing import ErrorHandlerCallable + +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.Optional[timedelta]) -> 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 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") + + #: The secure cookie uses this for the name of the session cookie. + #: + #: This attribute can also be configured from the config with the + #: ``SESSION_COOKIE_NAME`` configuration key. Defaults to ``'session'`` + session_cookie_name = ConfigAttribute("SESSION_COOKIE_NAME") + + #: 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 + ) + + #: A :class:`~datetime.timedelta` or number of seconds which is used + #: as the default ``max_age`` for :func:`send_file`. The default is + #: ``None``, which tells the browser to use conditional requests + #: instead of a timed cache. + #: + #: Configured with the :data:`SEND_FILE_MAX_AGE_DEFAULT` + #: configuration key. + #: + #: .. versionchanged:: 2.0 + #: Defaults to ``None`` instead of 12 hours. + send_file_max_age_default = ConfigAttribute( + "SEND_FILE_MAX_AGE_DEFAULT", get_converter=_make_timedelta + ) + + #: Enable this if you want to use the X-Sendfile feature. Keep in + #: mind that the server has to support this. This only affects files + #: sent with the :func:`send_file` method. + #: + #: .. versionadded:: 0.2 + #: + #: This attribute can also be configured from the config with the + #: ``USE_X_SENDFILE`` configuration key. Defaults to ``False``. + use_x_sendfile = ConfigAttribute("USE_X_SENDFILE") + + #: The JSON encoder class to use. Defaults to :class:`~flask.json.JSONEncoder`. + #: + #: .. versionadded:: 0.10 + json_encoder = json.JSONEncoder + + #: The JSON decoder class to use. Defaults to :class:`~flask.json.JSONDecoder`. + #: + #: .. versionadded:: 0.10 + json_decoder = json.JSONDecoder + + #: 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, + "PRESERVE_CONTEXT_ON_EXCEPTION": 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": True, + "JSON_SORT_KEYS": True, + "JSONIFY_PRETTYPRINT_REGULAR": False, + "JSONIFY_MIMETYPE": "application/json", + "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 = 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) + + #: A list of functions that are called when :meth:`url_for` raises a + #: :exc:`~werkzeug.routing.BuildError`. Each function registered here + #: is called with `error`, `endpoint` and `values`. If a function + #: returns ``None`` or raises a :exc:`BuildError` the next function is + #: tried. + #: + #: .. versionadded:: 0.9 + self.url_build_error_handlers: t.List[ + t.Callable[[Exception, str, dict], 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. + #: + #: .. versionadded:: 0.8 + self.before_first_request_funcs: t.List[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[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[t.Callable[[], t.Dict[str, t.Any]]] = [] + + #: 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 _is_setup_finished(self) -> bool: + return self.debug and self._got_first_request + + @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. + + .. versionadded:: 0.7 + """ + rv = self.config["PROPAGATE_EXCEPTIONS"] + if rv is not None: + return rv + return self.testing or self.debug + + @property + def preserve_context_on_exception(self) -> bool: + """Returns the value of the ``PRESERVE_CONTEXT_ON_EXCEPTION`` + configuration value in case it's set, otherwise a sensible default + is returned. + + .. versionadded:: 0.7 + """ + rv = self.config["PRESERVE_CONTEXT_ON_EXCEPTION"] + if rv is not None: + return rv + return 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"] = get_env() + defaults["DEBUG"] = get_debug_flag() + return self.config_class(root_path, defaults) + + 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`. + + This attribute can be configured with :data:`TEMPLATES_AUTO_RELOAD`. If + not set, it will be enabled in debug mode. + + .. versionadded:: 1.0 + This property was added but the underlying config and behavior + already existed. + """ + 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: + 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: + options["auto_reload"] = self.templates_auto_reload + + rv = self.jinja_environment(self, **options) + rv.globals.update( + url_for=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"] = 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 + + #: What environment the app is running in. Flask and extensions may + #: enable behaviors based on the environment, such as enabling debug + #: mode. This maps to the :data:`ENV` config key. This is set by the + #: :envvar:`FLASK_ENV` environment variable and may not behave as + #: expected if set in code. + #: + #: **Do not enable development when deploying in production.** + #: + #: Default: ``'production'`` + env = ConfigAttribute("ENV") + + @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. This is + enabled when :attr:`env` is ``'development'`` and is overridden + by the ``FLASK_DEBUG`` environment variable. It may not behave as + expected if set in code. + + **Do not enable debug mode when deploying in production.** + + Default: ``True`` if :attr:`env` is ``'development'``, or + ``False`` otherwise. + """ + return self.config["DEBUG"] + + @debug.setter + def debug(self, value: bool) -> None: + self.config["DEBUG"] = value + self.jinja_env.auto_reload = self.templates_auto_reload + + 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. + + If set, the :envvar:`FLASK_ENV` and :envvar:`FLASK_DEBUG` + environment variables will override :attr:`env` and + :attr:`debug`. + + Threaded mode is enabled by default. + + .. versionchanged:: 0.10 + The default port is now picked from the ``SERVER_NAME`` + variable. + """ + # Change this into a no-op if the server is invoked from the + # command line. Have a look at cli.py for more information. + if os.environ.get("FLASK_RUN_FROM_CLI") == "true": + from .debughelpers import explain_ignored_app_run + + explain_ignored_app_run() + return + + if get_load_dotenv(load_dotenv): + cli.load_dotenv() + + # if set, let env vars override previous values + if "FLASK_ENV" in os.environ: + self.env = get_env() + 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.env, self.debug, self.name, False) + + 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[t.Callable] = 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[[TemplateFilterCallable], TemplateFilterCallable]: + """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: TemplateFilterCallable) -> TemplateFilterCallable: + self.add_template_filter(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_filter( + self, f: 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[[TemplateTestCallable], TemplateTestCallable]: + """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: TemplateTestCallable) -> TemplateTestCallable: + self.add_template_test(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_test( + self, f: 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[[TemplateGlobalCallable], TemplateGlobalCallable]: + """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: TemplateGlobalCallable) -> TemplateGlobalCallable: + self.add_template_global(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_global( + self, f: 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: BeforeFirstRequestCallable + ) -> BeforeFirstRequestCallable: + """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. + + .. versionadded:: 0.8 + """ + self.before_first_request_funcs.append(f) + return f + + @setupmethod + def teardown_appcontext(self, f: TeardownCallable) -> TeardownCallable: + """Registers a function to be called when the application context + ends. These functions are typically also called when the request + context is popped. + + Example:: + + ctx = app.app_context() + ctx.push() + ... + ctx.pop() + + When ``ctx.pop()`` is executed in the above example, the teardown + functions are called just before the app context moves from the + stack of active contexts. This becomes relevant if you are using + such constructs in tests. + + 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. + + 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.Callable) -> t.Callable: + """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["ErrorHandlerCallable[Exception]"]: + """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, 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, 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) + + if self.propagate_exceptions: + # 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, 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": + """Exceptions that are recording during routing are reraised with + this method. During debug we are not reraising redirect requests + for non ``GET``, ``HEAD``, or ``OPTIONS`` requests and we're raising + a different error instead to help debug situations. + + :internal: + """ + if ( + not self.debug + or not isinstance(request.routing_exception, RequestRedirect) + or request.method in ("GET", "HEAD", "OPTIONS") + ): + raise request.routing_exception # type: ignore + + from .debughelpers import FormDataRoutingRedirect + + raise FormDataRoutingRedirect(request) + + def dispatch_request(self) -> 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_stack.top.request + if req.routing_exception is not None: + self.raise_routing_exception(req) + rule = req.url_rule + # 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 + return self.ensure_sync(self.view_functions[rule.endpoint])(**req.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 + """ + self.try_trigger_before_first_request_functions() + 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[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 try_trigger_before_first_request_functions(self) -> None: + """Called before each request and will ensure that it triggers + the :attr:`before_first_request_funcs` and only exactly once per + application instance (which means process usually). + + :internal: + """ + if self._got_first_request: + return + with self._before_request_lock: + if self._got_first_request: + return + for func in self.before_first_request_funcs: + self.ensure_sync(func)() + self._got_first_request = True + + 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_stack.top.url_adapter + methods = adapter.allowed_methods() + 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 + + # Check that Werkzeug isn't using its fallback ContextVar class. + if ContextVar.__module__ == "werkzeug.local": + raise RuntimeError( + "Async cannot be used with this combination of Python " + "and Greenlet versions." + ) + + return asgiref_async_to_sync(func) + + def make_response(self, rv: 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. + + ``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:: 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 + # 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 + # 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)): + # 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) + status = headers = None + elif isinstance(rv, dict): + rv = jsonify(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 # noqa: B950 + 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, tuple, Response instance, or WSGI" + f" callable, but it 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, tuple, Response instance, or WSGI" + f" callable, but it was a {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 # type: ignore + else: + rv.status_code = status + + # extend existing headers with provided headers + if headers: + rv.headers.update(headers) + + 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: Exception, endpoint: str, values: dict + ) -> str: + """Handle :class:`~werkzeug.routing.BuildError` on + :meth:`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[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_stack.top + + 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 self.should_ignore_error(error): + error = None + ctx.auto_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/src/myvenv/lib/python3.10/site-packages/flask/blueprints.py b/src/myvenv/lib/python3.10/site-packages/flask/blueprints.py new file mode 100644 index 0000000..5c23a73 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/flask/blueprints.py @@ -0,0 +1,609 @@ +import os +import typing as t +from collections import defaultdict +from functools import update_wrapper + +from .scaffold import _endpoint_from_view_func +from .scaffold import _sentinel +from .scaffold import Scaffold +from .typing import AfterRequestCallable +from .typing import BeforeFirstRequestCallable +from .typing import BeforeRequestCallable +from .typing import TeardownCallable +from .typing import TemplateContextProcessorCallable +from .typing import TemplateFilterCallable +from .typing import TemplateGlobalCallable +from .typing import TemplateTestCallable +from .typing import URLDefaultCallable +from .typing import URLValuePreprocessorCallable + +if t.TYPE_CHECKING: + from .app import Flask + from .typing import ErrorHandlerCallable + +DeferredSetupFunction = t.Callable[["BlueprintSetupState"], t.Callable] + + +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 + """ + + warn_on_modifications = False + _got_registered_once = False + + #: Blueprint local JSON encoder class to use. Set to ``None`` to use + #: the app's :class:`~flask.Flask.json_encoder`. + json_encoder = None + #: Blueprint local JSON decoder class to use. Set to ``None`` to use + #: the app's :class:`~flask.Flask.json_decoder`. + json_decoder = None + + 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 _is_setup_finished(self) -> bool: + return self.warn_on_modifications and self._got_registered_once + + 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. + """ + if self._got_registered_once and self.warn_on_modifications: + from warnings import warn + + warn( + Warning( + "The blueprint was already registered once but is" + " getting modified now. These changes will not show" + " up." + ) + ) + self.deferred_functions.append(func) + + 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) + + return 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) + + 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: + existing_at = f" '{name}'" if self_name != name else "" + + if app.blueprints[name] is not self: + raise ValueError( + f"The name '{self_name}' is already registered for" + f" a different blueprint{existing_at}. Use 'name='" + " to provide a unique name." + ) + else: + import warnings + + warnings.warn( + f"The name '{self_name}' is already registered for" + f" this blueprint{existing_at}. Use 'name=' to" + " provide a unique name. This will become an error" + " in Flask 2.1.", + stacklevel=4, + ) + + 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) + + def add_url_rule( + self, + rule: str, + endpoint: t.Optional[str] = None, + view_func: t.Optional[t.Callable] = 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, + ) + ) + + def app_template_filter( + self, name: t.Optional[str] = None + ) -> t.Callable[[TemplateFilterCallable], TemplateFilterCallable]: + """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: TemplateFilterCallable) -> TemplateFilterCallable: + self.add_app_template_filter(f, name=name) + return f + + return decorator + + def add_app_template_filter( + self, f: 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) + + def app_template_test( + self, name: t.Optional[str] = None + ) -> t.Callable[[TemplateTestCallable], TemplateTestCallable]: + """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: TemplateTestCallable) -> TemplateTestCallable: + self.add_app_template_test(f, name=name) + return f + + return decorator + + def add_app_template_test( + self, f: 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) + + def app_template_global( + self, name: t.Optional[str] = None + ) -> t.Callable[[TemplateGlobalCallable], TemplateGlobalCallable]: + """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: TemplateGlobalCallable) -> TemplateGlobalCallable: + self.add_app_template_global(f, name=name) + return f + + return decorator + + def add_app_template_global( + self, f: 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) + + def before_app_request(self, f: BeforeRequestCallable) -> BeforeRequestCallable: + """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 + + def before_app_first_request( + self, f: BeforeFirstRequestCallable + ) -> BeforeFirstRequestCallable: + """Like :meth:`Flask.before_first_request`. Such a function is + executed before the first request to the application. + """ + self.record_once(lambda s: s.app.before_first_request_funcs.append(f)) + return f + + def after_app_request(self, f: AfterRequestCallable) -> AfterRequestCallable: + """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 + + def teardown_app_request(self, f: TeardownCallable) -> TeardownCallable: + """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 + + def app_context_processor( + self, f: TemplateContextProcessorCallable + ) -> TemplateContextProcessorCallable: + """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 + + def app_errorhandler(self, code: t.Union[t.Type[Exception], int]) -> t.Callable: + """Like :meth:`Flask.errorhandler` but for a blueprint. This + handler is used for all requests, even if outside of the blueprint. + """ + + def decorator( + f: "ErrorHandlerCallable[Exception]", + ) -> "ErrorHandlerCallable[Exception]": + self.record_once(lambda s: s.app.errorhandler(code)(f)) + return f + + return decorator + + def app_url_value_preprocessor( + self, f: URLValuePreprocessorCallable + ) -> URLValuePreprocessorCallable: + """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 + + def app_url_defaults(self, f: URLDefaultCallable) -> URLDefaultCallable: + """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/src/myvenv/lib/python3.10/site-packages/flask/cli.py b/src/myvenv/lib/python3.10/site-packages/flask/cli.py new file mode 100644 index 0000000..8e21532 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/flask/cli.py @@ -0,0 +1,999 @@ +import ast +import inspect +import os +import platform +import re +import sys +import traceback +import warnings +from functools import update_wrapper +from operator import attrgetter +from threading import Lock +from threading import Thread + +import click +from werkzeug.utils import import_string + +from .globals import current_app +from .helpers import get_debug_flag +from .helpers import get_env +from .helpers import get_load_dotenv + +try: + import dotenv +except ImportError: + dotenv = None + +try: + import ssl +except ImportError: + ssl = None # type: ignore + + +class NoAppException(click.UsageError): + """Raised if an application cannot be found or loaded.""" + + +def find_best_app(script_info, 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__!r}. Use 'FLASK_APP={module.__name__}:name'" + f" 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 = call_factory(script_info, 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!r} in module {module.__name__!r}," + " but could not call it without arguments. Use" + f" \"FLASK_APP='{module.__name__}:{attr_name}(args)'\"" + " to specify arguments." + ) from e + + raise NoAppException( + "Failed to find Flask application or factory in module" + f" {module.__name__!r}. Use 'FLASK_APP={module.__name__}:name'" + " to specify one." + ) + + +def call_factory(script_info, app_factory, args=None, kwargs=None): + """Takes an app factory, a ``script_info` object and optionally a tuple + of arguments. Checks for the existence of a script_info argument and calls + the app_factory depending on that and the arguments provided. + """ + sig = inspect.signature(app_factory) + args = [] if args is None else args + kwargs = {} if kwargs is None else kwargs + + if "script_info" in sig.parameters: + warnings.warn( + "The 'script_info' argument is deprecated and will not be" + " passed to the app factory function in Flask 2.1.", + DeprecationWarning, + ) + kwargs["script_info"] = script_info + + if not args and len(sig.parameters) == 1: + first_parameter = next(iter(sig.parameters.values())) + + if ( + first_parameter.default is inspect.Parameter.empty + # **kwargs is reported as an empty default, ignore it + and first_parameter.kind is not inspect.Parameter.VAR_KEYWORD + ): + warnings.warn( + "Script info is deprecated and will not be passed as the" + " single argument to the app factory function in Flask" + " 2.1.", + DeprecationWarning, + ) + args.append(script_info) + + return app_factory(*args, **kwargs) + + +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(script_info, 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 = None + 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 = call_factory(script_info, 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(script_info, module_name, app_name, raise_if_not_found=True): + __traceback_hide__ = True # noqa: F841 + + 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(script_info, module) + else: + return find_app_by_string(script_info, 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 DispatchingApp: + """Special application that dispatches to a Flask application which + is imported by name in a background thread. If an error happens + it is recorded and shown as part of the WSGI handling which in case + of the Werkzeug debugger means that it shows up in the browser. + """ + + def __init__(self, loader, use_eager_loading=None): + self.loader = loader + self._app = None + self._lock = Lock() + self._bg_loading_exc = None + + if use_eager_loading is None: + use_eager_loading = os.environ.get("WERKZEUG_RUN_MAIN") != "true" + + if use_eager_loading: + self._load_unlocked() + else: + self._load_in_background() + + def _load_in_background(self): + def _load_app(): + __traceback_hide__ = True # noqa: F841 + with self._lock: + try: + self._load_unlocked() + except Exception as e: + self._bg_loading_exc = e + + t = Thread(target=_load_app, args=()) + t.start() + + def _flush_bg_loading_exception(self): + __traceback_hide__ = True # noqa: F841 + exc = self._bg_loading_exc + + if exc is not None: + self._bg_loading_exc = None + raise exc + + def _load_unlocked(self): + __traceback_hide__ = True # noqa: F841 + self._app = rv = self.loader() + self._bg_loading_exc = None + return rv + + def __call__(self, environ, start_response): + __traceback_hide__ = True # noqa: F841 + if self._app is not None: + return self._app(environ, start_response) + self._flush_bg_loading_exception() + with self._lock: + if self._app is not None: + rv = self._app + else: + rv = self._load_unlocked() + return rv(environ, start_response) + + +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=None, create_app=None, set_debug_flag=True): + #: Optionally the import path for the Flask application. + self.app_import_path = app_import_path or os.environ.get("FLASK_APP") + #: 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 = {} + self.set_debug_flag = set_debug_flag + self._loaded_app = None + + def load_app(self): + """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. + """ + __traceback_hide__ = True # noqa: F841 + + if self._loaded_app is not None: + return self._loaded_app + + if self.create_app is not None: + app = call_factory(self, 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(self, import_name, name) + else: + for path in ("wsgi.py", "app.py"): + import_name = prepare_import(path) + app = locate_app(self, import_name, None, raise_if_not_found=False) + + if app: + break + + if not app: + raise NoAppException( + "Could not locate a Flask application. You did not provide " + 'the "FLASK_APP" environment variable, and a "wsgi.py" or ' + '"app.py" module was not found 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. If callbacks are registered directly + to the ``app.cli`` object then they are wrapped with this function + by default unless it's disabled. + """ + + @click.pass_context + def decorator(__ctx, *args, **kwargs): + with __ctx.ensure_object(ScriptInfo).load_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) + + +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 based on the active + environment + + .. 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=True, + create_app=None, + add_version_option=True, + load_dotenv=True, + set_debug_flag=True, + **extra, + ): + params = list(extra.pop("params", None) or ()) + + if add_version_option: + params.append(version_option) + + AppGroup.__init__(self, 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 + try: + import pkg_resources + except ImportError: + self._loaded_plugin_commands = True + return + + for ep in pkg_resources.iter_entry_points("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: + return info.load_app().cli.get_command(ctx, name) + except NoAppException as e: + click.secho(f"Error: {e.format_message()}\n", err=True, fg="red") + + 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 main(self, *args, **kwargs): + # Set a global flag that indicates that we were invoked from the + # command line interface. This is detected by Flask.run to make the + # call into a no-op. This is necessary to avoid ugly errors when the + # script that is loaded here also attempts to start a server. + os.environ["FLASK_RUN_FROM_CLI"] = "true" + + if get_load_dotenv(self.load_dotenv): + load_dotenv() + + obj = kwargs.get("obj") + + if obj is None: + obj = ScriptInfo( + create_app=self.create_app, set_debug_flag=self.set_debug_flag + ) + + kwargs["obj"] = obj + kwargs.setdefault("auto_envvar_prefix", "FLASK") + return super().main(*args, **kwargs) + + +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=None): + """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:: 1.1.0 + Returns ``False`` when python-dotenv is not installed, or when + the given path isn't a file. + + .. versionchanged:: 2.0 + When loading the env files, set the default encoding to UTF-8. + + .. versionadded:: 1.0 + """ + if dotenv is None: + 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 + + # if the given path specifies the actual file then return True, + # else False + if path is not None: + if os.path.isfile(path): + return dotenv.load_dotenv(path, encoding="utf-8") + + return False + + new_dir = None + + for name in (".env", ".flaskenv"): + path = dotenv.find_dotenv(name, usecwd=True) + + if not path: + continue + + if new_dir is None: + new_dir = os.path.dirname(path) + + dotenv.load_dotenv(path, encoding="utf-8") + + return new_dir is not None # at least one file was located and loaded + + +def show_server_banner(env, debug, app_import_path, eager_loading): + """Show extra startup messages the first time the server is run, + ignoring the reloader. + """ + if os.environ.get("WERKZEUG_RUN_MAIN") == "true": + return + + if app_import_path is not None: + message = f" * Serving Flask app {app_import_path!r}" + + if not eager_loading: + message += " (lazy loading)" + + click.echo(message) + + click.echo(f" * Environment: {env}") + + if env == "production": + click.secho( + " WARNING: This is a development server. Do not use it in" + " a production deployment.", + fg="red", + ) + click.secho(" Use a production WSGI server instead.", dim=True) + + 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): + if ssl is None: + raise click.BadParameter( + 'Using "--cert" requires Python to be compiled with SSL support.', + ctx, + param, + ) + + 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" + is_context = ssl and 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." +) +@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( + "--eager-loading/--lazy-loading", + default=None, + help="Enable or disable eager loading. By default eager " + "loading is enabled if the reloader is disabled.", +) +@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}." + ), +) +@pass_script_info +def run_command( + info, host, port, reload, debugger, eager_loading, with_threads, cert, extra_files +): + """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 if + FLASK_ENV=development or FLASK_DEBUG=1. + """ + debug = get_debug_flag() + + if reload is None: + reload = debug + + if debugger is None: + debugger = debug + + show_server_banner(get_env(), debug, info.app_import_path, eager_loading) + app = DispatchingApp(info.load_app, use_eager_loading=eager_loading) + + from werkzeug.serving import run_simple + + run_simple( + host, + port, + app, + use_reloader=reload, + use_debugger=debugger, + threaded=with_threads, + ssl_context=cert, + extra_files=extra_files, + ) + + +@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 + from .globals import _app_ctx_stack + + app = _app_ctx_stack.top.app + banner = ( + f"Python {sys.version} on {sys.platform}\n" + f"App: {app.import_name} [{app.env}]\n" + f"Instance: {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(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( + help="""\ +A general utility script for Flask applications. + +Provides commands from Flask, extensions, and the application. Loads the +application defined in the FLASK_APP environment variable, or from a wsgi.py +file. Setting the FLASK_ENV environment variable to 'development' will enable +debug mode. + +\b + {prefix}{cmd} FLASK_APP=hello.py + {prefix}{cmd} FLASK_ENV=development + {prefix}flask run +""".format( + cmd="export" if os.name == "posix" else "set", + prefix="$ " if os.name == "posix" else "> ", + ) +) + + +def main() -> None: + if int(click.__version__[0]) < 8: + warnings.warn( + "Using the `flask` cli with Click 7 is deprecated and" + " will not be supported starting with Flask 2.1." + " Please upgrade to Click 8 as soon as possible.", + DeprecationWarning, + ) + # TODO omit sys.argv once https://github.com/pallets/click/issues/536 is fixed + cli.main(args=sys.argv[1:]) + + +if __name__ == "__main__": + main() diff --git a/src/myvenv/lib/python3.10/site-packages/flask/config.py b/src/myvenv/lib/python3.10/site-packages/flask/config.py new file mode 100644 index 0000000..ca76902 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/flask/config.py @@ -0,0 +1,295 @@ +import errno +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: + dict.__init__(self, 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_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 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_json(self, filename: str, silent: bool = False) -> bool: + """Update the values in the config from a JSON file. The loaded + data is passed to the :meth:`from_mapping` method. + + :param filename: The path to the JSON file. This can be an + absolute path or relative to the config root path. + :param silent: Ignore the file if it doesn't exist. + :return: ``True`` if the file was loaded successfully. + + .. deprecated:: 2.0.0 + Will be removed in Flask 2.1. Use :meth:`from_file` instead. + This was removed early in 2.0.0, was added back in 2.0.1. + + .. versionadded:: 0.11 + """ + import warnings + from . import json + + warnings.warn( + "'from_json' is deprecated and will be removed in Flask" + " 2.1. Use 'from_file(path, json.load)' instead.", + DeprecationWarning, + stacklevel=2, + ) + return self.from_file(filename, json.load, silent=silent) + + 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/src/myvenv/lib/python3.10/site-packages/flask/ctx.py b/src/myvenv/lib/python3.10/site-packages/flask/ctx.py new file mode 100644 index 0000000..47465fd --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/flask/ctx.py @@ -0,0 +1,489 @@ +import sys +import typing as t +from functools import update_wrapper +from types import TracebackType + +from werkzeug.exceptions import HTTPException + +from .globals import _app_ctx_stack +from .globals import _request_ctx_stack +from .signals import appcontext_popped +from .signals import appcontext_pushed +from .typing import AfterRequestCallable + +if t.TYPE_CHECKING: + 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: + top = _app_ctx_stack.top + if top is not None: + return f"" + return object.__repr__(self) + + +def after_this_request(f: AfterRequestCallable) -> 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 + """ + top = _request_ctx_stack.top + + if top is None: + raise RuntimeError( + "This decorator can only be used when a request context is" + " active, such as within a view function." + ) + + top._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 + """ + top = _request_ctx_stack.top + + if top is None: + raise RuntimeError( + "This decorator can only be used when a request context is" + " active, such as within a view function." + ) + + reqctx = top.copy() + + def wrapper(*args, **kwargs): + with reqctx: + return 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 _request_ctx_stack.top 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 _app_ctx_stack.top is not None + + +class AppContext: + """The application context binds an application object implicitly + to the current thread or greenlet, similar to how the + :class:`RequestContext` binds request information. The application + context is also implicitly created if a request context is created + but the application is not on top of the individual application + context. + """ + + def __init__(self, app: "Flask") -> None: + self.app = app + self.url_adapter = app.create_url_adapter(None) + self.g = app.app_ctx_globals_class() + + # Like request context, app contexts can be pushed multiple times + # but there a basic "refcount" is enough to track them. + self._refcnt = 0 + + def push(self) -> None: + """Binds the app context to the current context.""" + self._refcnt += 1 + _app_ctx_stack.push(self) + appcontext_pushed.send(self.app) + + def pop(self, exc: t.Optional[BaseException] = _sentinel) -> None: # type: ignore + """Pops the app context.""" + try: + self._refcnt -= 1 + if self._refcnt <= 0: + if exc is _sentinel: + exc = sys.exc_info()[1] + self.app.do_teardown_appcontext(exc) + finally: + rv = _app_ctx_stack.pop() + assert rv is self, f"Popped wrong app context. ({rv!r} instead of {self!r})" + appcontext_popped.send(self.app) + + def __enter__(self) -> "AppContext": + self.push() + return self + + def __exit__( + self, exc_type: type, exc_value: BaseException, tb: TracebackType + ) -> None: + self.pop(exc_value) + + +class RequestContext: + """The request context contains all request relevant information. It is + created at the beginning of the request and pushed to the + `_request_ctx_stack` and removed at the end of it. 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 + for you. In debug mode the request context is kept around if + exceptions happen so that interactive debuggers have a chance to + introspect the data. With 0.4 this can also be forced for requests + that did not fail and outside of ``DEBUG`` mode. By setting + ``'flask._preserve_context'`` to ``True`` on the WSGI environment the + context will not pop itself at the end of the request. This is used by + the :meth:`~flask.Flask.test_client` for example to implement the + deferred cleanup functionality. + + You might find this helpful for unittests where you need the + information from the context local around for a little longer. Make + sure to properly :meth:`~werkzeug.LocalStack.pop` the stack yourself in + that situation, otherwise your unittests will leak memory. + """ + + 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) + self.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 = None + self.session = session + + # Request contexts can be pushed multiple times and interleaved with + # other request contexts. Now only if the last level is popped we + # get rid of them. Additionally if an application context is missing + # one is created implicitly so for each level we add this information + self._implicit_app_ctx_stack: t.List[t.Optional["AppContext"]] = [] + + # indicator if the context was preserved. Next time another context + # is pushed the preserved context is popped. + self.preserved = False + + # remembers the exception for pop if there is one in case the context + # preservation kicks in. + self._preserved_exc = None + + # 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[AfterRequestCallable] = [] + + @property + def g(self) -> AppContext: + return _app_ctx_stack.top.g + + @g.setter + def g(self, value: AppContext) -> None: + _app_ctx_stack.top.g = value + + 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: + """Binds the request context to the current context.""" + # If an exception occurs in debug mode or if context preservation is + # activated under exception situations exactly one context stays + # on the stack. The rationale is that you want to access that + # information under debug situations. However if someone forgets to + # pop that context again we want to make sure that on the next push + # it's invalidated, otherwise we run at risk that something leaks + # memory. This is usually only a problem in test suite since this + # functionality is not active in production environments. + top = _request_ctx_stack.top + if top is not None and top.preserved: + top.pop(top._preserved_exc) + + # Before we push the request context we have to ensure that there + # is an application context. + app_ctx = _app_ctx_stack.top + if app_ctx is None or app_ctx.app != self.app: + app_ctx = self.app.app_context() + app_ctx.push() + self._implicit_app_ctx_stack.append(app_ctx) + else: + self._implicit_app_ctx_stack.append(None) + + _request_ctx_stack.push(self) + + # 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. + """ + app_ctx = self._implicit_app_ctx_stack.pop() + clear_request = False + + try: + if not self._implicit_app_ctx_stack: + self.preserved = False + self._preserved_exc = None + 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() + clear_request = True + finally: + rv = _request_ctx_stack.pop() + + # 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: + rv.request.environ["werkzeug.request"] = None + + # Get rid of the app as well if necessary. + if app_ctx is not None: + app_ctx.pop(exc) + + assert ( + rv is self + ), f"Popped wrong request context. ({rv!r} instead of {self!r})" + + def auto_pop(self, exc: t.Optional[BaseException]) -> None: + if self.request.environ.get("flask._preserve_context") or ( + exc is not None and self.app.preserve_context_on_exception + ): + self.preserved = True + self._preserved_exc = exc # type: ignore + else: + self.pop(exc) + + def __enter__(self) -> "RequestContext": + self.push() + return self + + def __exit__( + self, exc_type: type, exc_value: BaseException, tb: TracebackType + ) -> None: + # do not pop the request stack if we are in debug mode and an + # exception happened. This will allow the debugger to still + # access the request object in the interactive shell. Furthermore + # the context can be force kept alive for the test client. + # See flask.testing for how this works. + self.auto_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/src/myvenv/lib/python3.10/site-packages/flask/debughelpers.py b/src/myvenv/lib/python3.10/site-packages/flask/debughelpers.py new file mode 100644 index 0000000..212f7d7 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/flask/debughelpers.py @@ -0,0 +1,172 @@ +import os +import typing as t +from warnings import warn + +from .app import Flask +from .blueprints import Blueprint +from .globals import _request_ctx_stack + + +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 by Flask in debug mode if it detects a + redirect caused by the routing system when the request method is not + GET, HEAD or OPTIONS. Reasoning: form data will be dropped. + """ + + def __init__(self, request): + exc = request.routing_exception + buf = [ + f"A request was sent to this URL ({request.url}) but a" + " redirect was issued automatically by the routing system" + f" to {exc.new_url!r}." + ] + + # In case just a slash was appended we can be extra helpful + if f"{request.base_url}/" == exc.new_url.split("?")[0]: + buf.append( + " The URL was defined with a trailing slash so Flask" + " will automatically redirect to the URL with the" + " trailing slash if it was accessed without one." + ) + + buf.append( + " Make sure to directly send your" + f" {request.method}-request to this URL since we can't make" + " browsers or HTTP clients redirect with form data reliably" + " or without user interaction." + ) + buf.append("\n\nNote: this exception is only raised in debug mode") + AssertionError.__init__(self, "".join(buf).encode("utf-8")) + + +def attach_enctype_error_multidict(request): + """Since Flask 0.8 we're monkeypatching the files object in case a + request is detected that does not use multipart form data but the files + object is accessed. + """ + oldcls = request.files.__class__ + + class newcls(oldcls): + def __getitem__(self, key): + try: + return oldcls.__getitem__(self, key) + except KeyError as e: + if key not in request.form: + raise + + raise DebugFilesKeyError(request, key) from e + + 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 + reqctx = _request_ctx_stack.top + if reqctx is not None and reqctx.request.blueprint is not None: + blueprint = reqctx.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)) + + +def explain_ignored_app_run() -> None: + if os.environ.get("WERKZEUG_RUN_MAIN") != "true": + warn( + Warning( + "Silently ignoring app.run() because the application is" + " run from the flask command line executable. Consider" + ' putting app.run() behind an if __name__ == "__main__"' + " guard to silence this warning." + ), + stacklevel=3, + ) diff --git a/src/myvenv/lib/python3.10/site-packages/flask/globals.py b/src/myvenv/lib/python3.10/site-packages/flask/globals.py new file mode 100644 index 0000000..6d91c75 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/flask/globals.py @@ -0,0 +1,59 @@ +import typing as t +from functools import partial + +from werkzeug.local import LocalProxy +from werkzeug.local import LocalStack + +if t.TYPE_CHECKING: + from .app import Flask + from .ctx import _AppCtxGlobals + from .sessions import SessionMixin + from .wrappers import Request + +_request_ctx_err_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.\ +""" +_app_ctx_err_msg = """\ +Working outside of application context. + +This typically means that you attempted to use functionality that needed +to interface with the current application object in some way. To solve +this, set up an application context with app.app_context(). See the +documentation for more information.\ +""" + + +def _lookup_req_object(name): + top = _request_ctx_stack.top + if top is None: + raise RuntimeError(_request_ctx_err_msg) + return getattr(top, name) + + +def _lookup_app_object(name): + top = _app_ctx_stack.top + if top is None: + raise RuntimeError(_app_ctx_err_msg) + return getattr(top, name) + + +def _find_app(): + top = _app_ctx_stack.top + if top is None: + raise RuntimeError(_app_ctx_err_msg) + return top.app + + +# context locals +_request_ctx_stack = LocalStack() +_app_ctx_stack = LocalStack() +current_app: "Flask" = LocalProxy(_find_app) # type: ignore +request: "Request" = LocalProxy(partial(_lookup_req_object, "request")) # type: ignore +session: "SessionMixin" = LocalProxy( # type: ignore + partial(_lookup_req_object, "session") +) +g: "_AppCtxGlobals" = LocalProxy(partial(_lookup_app_object, "g")) # type: ignore diff --git a/src/myvenv/lib/python3.10/site-packages/flask/helpers.py b/src/myvenv/lib/python3.10/site-packages/flask/helpers.py new file mode 100644 index 0000000..4359780 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/flask/helpers.py @@ -0,0 +1,836 @@ +import os +import pkgutil +import socket +import sys +import typing as t +import warnings +from datetime import datetime +from datetime import timedelta +from functools import lru_cache +from functools import update_wrapper +from threading import RLock + +import werkzeug.utils +from werkzeug.exceptions import NotFound +from werkzeug.routing import BuildError +from werkzeug.urls import url_quote + +from .globals import _app_ctx_stack +from .globals import _request_ctx_stack +from .globals import current_app +from .globals import request +from .globals import session +from .signals import message_flashed + +if t.TYPE_CHECKING: + from .wrappers import Response + + +def get_env() -> str: + """Get the environment the app is running in, indicated by the + :envvar:`FLASK_ENV` environment variable. The default is + ``'production'``. + """ + 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 + ``True`` if :func:`.get_env` returns ``'development'``, or ``False`` + otherwise. + """ + val = os.environ.get("FLASK_DEBUG") + + if not val: + return get_env() == "development" + + return val.lower() not in ("0", "false", "no") + + +def get_load_dotenv(default: bool = True) -> bool: + """Get whether the user has disabled loading 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 = _request_ctx_stack.top + if ctx is None: + raise RuntimeError( + "Attempted to stream with context but " + "there was no context in the first place to keep around." + ) + 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) + + +def url_for(endpoint: str, **values: t.Any) -> str: + """Generates a URL to the given endpoint with the method provided. + + Variable arguments that are unknown to the target endpoint are appended + to the generated URL as query arguments. If the value of a query argument + is ``None``, the whole pair is skipped. In case blueprints are active + you can shortcut references to the same blueprint by prefixing the + local endpoint with a dot (``.``). + + This will reference the index function local to the current blueprint:: + + url_for('.index') + + See :ref:`url-building`. + + Configuration values ``APPLICATION_ROOT`` and ``SERVER_NAME`` are only used when + generating URLs outside of a request context. + + To integrate applications, :class:`Flask` has a hook to intercept URL build + errors through :attr:`Flask.url_build_error_handlers`. The `url_for` + function results in a :exc:`~werkzeug.routing.BuildError` when the current + app does not have a URL for the given endpoint and values. When it does, the + :data:`~flask.current_app` calls its :attr:`~Flask.url_build_error_handlers` if + it is not ``None``, which can return a string to use as the result of + `url_for` (instead of `url_for`'s default to raise the + :exc:`~werkzeug.routing.BuildError` exception) or re-raise the exception. + An example:: + + def external_url_handler(error, endpoint, values): + "Looks up an external URL when `url_for` cannot build a URL." + # This is an example of hooking the build_error_handler. + # Here, lookup_url is some utility function you've built + # which looks up the endpoint in some external URL registry. + url = lookup_url(endpoint, **values) + if url is None: + # External lookup did not have a URL. + # Re-raise the BuildError, in context of original traceback. + exc_type, exc_value, tb = sys.exc_info() + if exc_value is error: + raise exc_type(exc_value).with_traceback(tb) + else: + raise error + # url_for will use this result, instead of raising BuildError. + return url + + app.url_build_error_handlers.append(external_url_handler) + + Here, `error` is the instance of :exc:`~werkzeug.routing.BuildError`, and + `endpoint` and `values` are the arguments passed into `url_for`. Note + that this is for building URLs outside the current application, and not for + handling 404 NotFound errors. + + .. versionadded:: 0.10 + The `_scheme` parameter was added. + + .. versionadded:: 0.9 + The `_anchor` and `_method` parameters were added. + + .. versionadded:: 0.9 + Calls :meth:`Flask.handle_build_error` on + :exc:`~werkzeug.routing.BuildError`. + + :param endpoint: the endpoint of the URL (name of the function) + :param values: the variable arguments of the URL rule + :param _external: if set to ``True``, an absolute URL is generated. Server + address can be changed via ``SERVER_NAME`` configuration variable which + falls back to the `Host` header, then to the IP and port of the request. + :param _scheme: a string specifying the desired URL scheme. The `_external` + parameter must be set to ``True`` or a :exc:`ValueError` is raised. The default + behavior uses the same scheme as the current request, or + :data:`PREFERRED_URL_SCHEME` if no request context is available. + This also can be set to an empty string to build protocol-relative + URLs. + :param _anchor: if provided this is added as anchor to the URL. + :param _method: if provided this explicitly specifies an HTTP method. + """ + appctx = _app_ctx_stack.top + reqctx = _request_ctx_stack.top + + if appctx is None: + raise RuntimeError( + "Attempted to generate a URL without the application context being" + " pushed. This has to be executed when application context is" + " available." + ) + + # If request specific information is available we have some extra + # features that support "relative" URLs. + if reqctx is not None: + url_adapter = reqctx.url_adapter + blueprint_name = request.blueprint + + if endpoint[:1] == ".": + if blueprint_name is not None: + endpoint = f"{blueprint_name}{endpoint}" + else: + endpoint = endpoint[1:] + + external = values.pop("_external", False) + + # Otherwise go with the url adapter from the appctx and make + # the URLs external by default. + else: + url_adapter = appctx.url_adapter + + if url_adapter is None: + raise RuntimeError( + "Application was not able to create a URL adapter for request" + " independent URL generation. You might be able to fix this by" + " setting the SERVER_NAME config variable." + ) + + external = values.pop("_external", True) + + anchor = values.pop("_anchor", None) + method = values.pop("_method", None) + scheme = values.pop("_scheme", None) + appctx.app.inject_url_defaults(endpoint, values) + + # This is not the best way to deal with this but currently the + # underlying Werkzeug router does not support overriding the scheme on + # a per build call basis. + old_scheme = None + if scheme is not None: + if not external: + raise ValueError("When specifying _scheme, _external must be True") + old_scheme = url_adapter.url_scheme + url_adapter.url_scheme = scheme + + try: + try: + rv = url_adapter.build( + endpoint, values, method=method, force_external=external + ) + finally: + if old_scheme is not None: + url_adapter.url_scheme = old_scheme + except BuildError as error: + # We need to inject the values again so that the app callback can + # deal with that sort of stuff. + values["_external"] = external + values["_anchor"] = anchor + values["_method"] = method + values["_scheme"] = scheme + return appctx.app.handle_url_build_error(error, endpoint, values) + + if anchor is not None: + rv += f"#{url_quote(anchor)}" + return rv + + +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_stack.top.flashes + if flashes is None: + _request_ctx_stack.top.flashes = flashes = ( + session.pop("_flashes") if "_flashes" in session else [] + ) + 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( + download_name: t.Optional[str] = None, + attachment_filename: t.Optional[str] = None, + etag: t.Optional[t.Union[bool, str]] = None, + add_etags: t.Optional[t.Union[bool]] = None, + max_age: t.Optional[ + t.Union[int, t.Callable[[t.Optional[str]], t.Optional[int]]] + ] = None, + cache_timeout: t.Optional[int] = None, + **kwargs: t.Any, +) -> t.Dict[str, t.Any]: + if attachment_filename is not None: + warnings.warn( + "The 'attachment_filename' parameter has been renamed to" + " 'download_name'. The old name will be removed in Flask" + " 2.1.", + DeprecationWarning, + stacklevel=3, + ) + download_name = attachment_filename + + if cache_timeout is not None: + warnings.warn( + "The 'cache_timeout' parameter has been renamed to" + " 'max_age'. The old name will be removed in Flask 2.1.", + DeprecationWarning, + stacklevel=3, + ) + max_age = cache_timeout + + if add_etags is not None: + warnings.warn( + "The 'add_etags' parameter has been renamed to 'etag'. The" + " old name will be removed in Flask 2.1.", + DeprecationWarning, + stacklevel=3, + ) + etag = add_etags + + if max_age is None: + max_age = current_app.get_send_file_max_age + + kwargs.update( + environ=request.environ, + download_name=download_name, + etag=etag, + max_age=max_age, + use_x_sendfile=current_app.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, + attachment_filename: t.Optional[str] = None, + conditional: bool = True, + etag: t.Union[bool, str] = True, + add_etags: t.Optional[bool] = None, + 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, + cache_timeout: t.Optional[int] = None, +): + """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( + **_prepare_send_file_kwargs( + path_or_file=path_or_file, + environ=request.environ, + mimetype=mimetype, + as_attachment=as_attachment, + download_name=download_name, + attachment_filename=attachment_filename, + conditional=conditional, + etag=etag, + add_etags=add_etags, + last_modified=last_modified, + max_age=max_age, + cache_timeout=cache_timeout, + ) + ) + + +def safe_join(directory: str, *pathnames: str) -> 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``. + """ + warnings.warn( + "'flask.helpers.safe_join' is deprecated and will be removed in" + " Flask 2.1. Use 'werkzeug.utils.safe_join' instead.", + DeprecationWarning, + stacklevel=2, + ) + path = werkzeug.utils.safe_join(directory, *pathnames) + + if path is None: + raise NotFound() + + return path + + +def send_from_directory( + directory: t.Union[os.PathLike, str], + path: t.Union[os.PathLike, str], + filename: t.Optional[str] = None, + **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. + :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 + """ + if filename is not None: + warnings.warn( + "The 'filename' parameter has been renamed to 'path'. The" + " old name will be removed in Flask 2.1.", + DeprecationWarning, + stacklevel=2, + ) + path = filename + + return werkzeug.utils.send_from_directory( # type: ignore + 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 total_seconds(td: timedelta) -> int: + """Returns the total seconds from a timedelta object. + + :param timedelta td: the timedelta to be converted in seconds + + :returns: number of seconds + :rtype: int + + .. deprecated:: 2.0 + Will be removed in Flask 2.1. Use + :meth:`timedelta.total_seconds` instead. + """ + warnings.warn( + "'total_seconds' is deprecated and will be removed in Flask" + " 2.1. Use 'timedelta.total_seconds' instead.", + DeprecationWarning, + stacklevel=2, + ) + return td.days * 60 * 60 * 24 + td.seconds + + +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/src/myvenv/lib/python3.10/site-packages/flask/json/__init__.py b/src/myvenv/lib/python3.10/site-packages/flask/json/__init__.py new file mode 100644 index 0000000..ccb9efb --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/flask/json/__init__.py @@ -0,0 +1,363 @@ +import decimal +import io +import json as _json +import typing as t +import uuid +import warnings +from datetime import date + +from jinja2.utils import htmlsafe_json_dumps as _jinja_htmlsafe_dumps +from werkzeug.http import http_date + +from ..globals import current_app +from ..globals import request + +if t.TYPE_CHECKING: + from ..app import Flask + from ..wrappers import Response + +try: + import dataclasses +except ImportError: + # Python < 3.7 + dataclasses = None # type: ignore + + +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:`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. + """ + + 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. + """ + if isinstance(o, date): + return http_date(o) + if isinstance(o, (decimal.Decimal, uuid.UUID)): + return str(o) + if dataclasses and dataclasses.is_dataclass(o): + return dataclasses.asdict(o) + if hasattr(o, "__html__"): + return str(o.__html__()) + return super().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. + """ + + +def _dump_arg_defaults( + kwargs: t.Dict[str, t.Any], app: t.Optional["Flask"] = None +) -> None: + """Inject default arguments for dump functions.""" + if app is None: + app = current_app + + if app: + cls = app.json_encoder + bp = app.blueprints.get(request.blueprint) if request else None # type: ignore + if bp is not None and bp.json_encoder is not None: + cls = bp.json_encoder + + # Only set a custom encoder if it has custom behavior. This is + # faster on PyPy. + if cls is not _json.JSONEncoder: + kwargs.setdefault("cls", cls) + + kwargs.setdefault("cls", cls) + kwargs.setdefault("ensure_ascii", app.config["JSON_AS_ASCII"]) + kwargs.setdefault("sort_keys", app.config["JSON_SORT_KEYS"]) + else: + kwargs.setdefault("sort_keys", True) + kwargs.setdefault("cls", JSONEncoder) + + +def _load_arg_defaults( + kwargs: t.Dict[str, t.Any], app: t.Optional["Flask"] = None +) -> None: + """Inject default arguments for load functions.""" + if app is None: + app = current_app + + if app: + cls = app.json_decoder + bp = app.blueprints.get(request.blueprint) if request else None # type: ignore + if bp is not None and bp.json_decoder is not None: + cls = bp.json_decoder + + # Only set a custom decoder if it has custom behavior. This is + # faster on PyPy. + if cls not in {JSONDecoder, _json.JSONDecoder}: + kwargs.setdefault("cls", cls) + + +def dumps(obj: t.Any, app: t.Optional["Flask"] = None, **kwargs: t.Any) -> str: + """Serialize an object to a string of JSON. + + Takes the same arguments as the built-in :func:`json.dumps`, with + some defaults from application configuration. + + :param obj: Object to serialize to JSON. + :param app: Use this app's config instead of the active app context + or defaults. + :param kwargs: Extra arguments passed to :func:`json.dumps`. + + .. versionchanged:: 2.0.2 + :class:`decimal.Decimal` is supported by converting to a string. + + .. versionchanged:: 2.0 + ``encoding`` is deprecated and will be removed in Flask 2.1. + + .. versionchanged:: 1.0.3 + ``app`` can be passed directly, rather than requiring an app + context for configuration. + """ + _dump_arg_defaults(kwargs, app=app) + encoding = kwargs.pop("encoding", None) + rv = _json.dumps(obj, **kwargs) + + if encoding is not None: + warnings.warn( + "'encoding' is deprecated and will be removed in Flask 2.1.", + DeprecationWarning, + stacklevel=2, + ) + + if isinstance(rv, str): + return rv.encode(encoding) # type: ignore + + return rv + + +def dump( + obj: t.Any, fp: t.IO[str], app: t.Optional["Flask"] = None, **kwargs: t.Any +) -> None: + """Serialize an object to JSON written to a file object. + + Takes the same arguments as the built-in :func:`json.dump`, with + some defaults from application configuration. + + :param obj: Object to serialize to JSON. + :param fp: File object to write JSON to. + :param app: Use this app's config instead of the active app context + or defaults. + :param kwargs: Extra arguments passed to :func:`json.dump`. + + .. versionchanged:: 2.0 + Writing to a binary file, and the ``encoding`` argument, is + deprecated and will be removed in Flask 2.1. + """ + _dump_arg_defaults(kwargs, app=app) + encoding = kwargs.pop("encoding", None) + show_warning = encoding is not None + + try: + fp.write("") + except TypeError: + show_warning = True + fp = io.TextIOWrapper(fp, encoding or "utf-8") # type: ignore + + if show_warning: + warnings.warn( + "Writing to a binary file, and the 'encoding' argument, is" + " deprecated and will be removed in Flask 2.1.", + DeprecationWarning, + stacklevel=2, + ) + + _json.dump(obj, fp, **kwargs) + + +def loads(s: str, app: t.Optional["Flask"] = None, **kwargs: t.Any) -> t.Any: + """Deserialize an object from a string of JSON. + + Takes the same arguments as the built-in :func:`json.loads`, with + some defaults from application configuration. + + :param s: JSON string to deserialize. + :param app: Use this app's config instead of the active app context + or defaults. + :param kwargs: Extra arguments passed to :func:`json.loads`. + + .. versionchanged:: 2.0 + ``encoding`` is deprecated and 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. + """ + _load_arg_defaults(kwargs, app=app) + encoding = kwargs.pop("encoding", None) + + if encoding is not None: + warnings.warn( + "'encoding' is deprecated and will be removed in Flask 2.1." + " The data must be a string or UTF-8 bytes.", + DeprecationWarning, + stacklevel=2, + ) + + if isinstance(s, bytes): + s = s.decode(encoding) + + return _json.loads(s, **kwargs) + + +def load(fp: t.IO[str], app: t.Optional["Flask"] = None, **kwargs: t.Any) -> t.Any: + """Deserialize an object from JSON read from a file object. + + Takes the same arguments as the built-in :func:`json.load`, with + some defaults from application configuration. + + :param fp: File object to read JSON from. + :param app: Use this app's config instead of the active app context + or defaults. + :param kwargs: Extra arguments passed to :func:`json.load`. + + .. versionchanged:: 2.0 + ``encoding`` is deprecated and will be removed in Flask 2.1. The + file must be text mode, or binary mode with UTF-8 bytes. + """ + _load_arg_defaults(kwargs, app=app) + encoding = kwargs.pop("encoding", None) + + if encoding is not None: + warnings.warn( + "'encoding' is deprecated and will be removed in Flask 2.1." + " The file must be text mode, or binary mode with UTF-8" + " bytes.", + DeprecationWarning, + stacklevel=2, + ) + + if isinstance(fp.read(0), bytes): + fp = io.TextIOWrapper(fp, encoding) # type: ignore + + 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/src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/whitespace.py b/src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/whitespace.py new file mode 100644 index 0000000..0d12584 --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/html5parser.py b/src/myvenv/lib/python3.10/site-packages/pip/_vendor/html5lib/html5parser.py new file mode 100644 index 0000000..d06784f --- /dev/null +++ b/src/myvenv/lib/python3.10/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
+
+""" + +SOURCE_LINE_HTML = """\ + + %(lineno)s + %(code)s + +""" + + +def render_console_html(secret: str, evalex_trusted: bool = True) -> str: + return CONSOLE_HTML % { + "evalex": "true", + "evalex_trusted": "true" if evalex_trusted else "false", + "console": "true", + "title": "Console", + "secret": secret, + "traceback_id": -1, + } + + +def get_current_traceback( + ignore_system_exceptions: bool = False, + show_hidden_frames: bool = False, + skip: int = 0, +) -> "Traceback": + """Get the current exception info as `Traceback` object. Per default + calling this method will reraise system exceptions such as generator exit, + system exit or others. This behavior can be disabled by passing `False` + to the function as first parameter. + """ + info = t.cast( + t.Tuple[t.Type[BaseException], BaseException, TracebackType], sys.exc_info() + ) + exc_type, exc_value, tb = info + + if ignore_system_exceptions and exc_type in { + SystemExit, + KeyboardInterrupt, + GeneratorExit, + }: + raise + for _ in range(skip): + if tb.tb_next is None: + break + tb = tb.tb_next + tb = Traceback(exc_type, exc_value, tb) + if not show_hidden_frames: + tb.filter_hidden_frames() + return tb + + +class Line: + """Helper for the source renderer.""" + + __slots__ = ("lineno", "code", "in_frame", "current") + + def __init__(self, lineno: int, code: str) -> None: + self.lineno = lineno + self.code = code + self.in_frame = False + self.current = False + + @property + def classes(self) -> t.List[str]: + rv = ["line"] + if self.in_frame: + rv.append("in-frame") + if self.current: + rv.append("current") + return rv + + def render(self) -> str: + return SOURCE_LINE_HTML % { + "classes": " ".join(self.classes), + "lineno": self.lineno, + "code": escape(self.code), + } + + +class Traceback: + """Wraps a traceback.""" + + def __init__( + self, + exc_type: t.Type[BaseException], + exc_value: BaseException, + tb: TracebackType, + ) -> None: + self.exc_type = exc_type + self.exc_value = exc_value + self.tb = tb + + exception_type = exc_type.__name__ + if exc_type.__module__ not in {"builtins", "__builtin__", "exceptions"}: + exception_type = f"{exc_type.__module__}.{exception_type}" + self.exception_type = exception_type + + self.groups = [] + memo = set() + while True: + self.groups.append(Group(exc_type, exc_value, tb)) + memo.add(id(exc_value)) + exc_value = exc_value.__cause__ or exc_value.__context__ # type: ignore + if exc_value is None or id(exc_value) in memo: + break + exc_type = type(exc_value) + tb = exc_value.__traceback__ # type: ignore + self.groups.reverse() + self.frames = [frame for group in self.groups for frame in group.frames] + + def filter_hidden_frames(self) -> None: + """Remove the frames according to the paste spec.""" + for group in self.groups: + group.filter_hidden_frames() + + self.frames[:] = [frame for group in self.groups for frame in group.frames] + + @property + def is_syntax_error(self) -> bool: + """Is it a syntax error?""" + return isinstance(self.exc_value, SyntaxError) + + @property + def exception(self) -> str: + """String representation of the final exception.""" + return self.groups[-1].exception + + def log(self, logfile: t.Optional[t.IO[str]] = None) -> None: + """Log the ASCII traceback into a file object.""" + if logfile is None: + logfile = sys.stderr + tb = f"{self.plaintext.rstrip()}\n" + logfile.write(tb) + + def render_summary(self, include_title: bool = True) -> str: + """Render the traceback for the interactive console.""" + title = "" + classes = ["traceback"] + if not self.frames: + classes.append("noframe-traceback") + frames = [] + else: + library_frames = sum(frame.is_library for frame in self.frames) + mark_lib = 0 < library_frames < len(self.frames) + frames = [group.render(mark_lib=mark_lib) for group in self.groups] + + if include_title: + if self.is_syntax_error: + title = "Syntax Error" + else: + title = "Traceback (most recent call last):" + + if self.is_syntax_error: + description = f"
{escape(self.exception)}
" + else: + description = f"
{escape(self.exception)}
" + + return SUMMARY_HTML % { + "classes": " ".join(classes), + "title": f"

{title if title else ''}

", + "frames": "\n".join(frames), + "description": description, + } + + def render_full( + self, + evalex: bool = False, + secret: t.Optional[str] = None, + evalex_trusted: bool = True, + ) -> str: + """Render the Full HTML page with the traceback info.""" + exc = escape(self.exception) + return PAGE_HTML % { + "evalex": "true" if evalex else "false", + "evalex_trusted": "true" if evalex_trusted else "false", + "console": "false", + "title": exc, + "exception": exc, + "exception_type": escape(self.exception_type), + "summary": self.render_summary(include_title=False), + "plaintext": escape(self.plaintext), + "plaintext_cs": re.sub("-{2,}", "-", self.plaintext), + "traceback_id": self.id, + "secret": secret, + } + + @cached_property + def plaintext(self) -> str: + return "\n".join([group.render_text() for group in self.groups]) + + @property + def id(self) -> int: + return id(self) + + +class Group: + """A group of frames for an exception in a traceback. If the + exception has a ``__cause__`` or ``__context__``, there are multiple + exception groups. + """ + + def __init__( + self, + exc_type: t.Type[BaseException], + exc_value: BaseException, + tb: TracebackType, + ) -> None: + self.exc_type = exc_type + self.exc_value = exc_value + self.info = None + if exc_value.__cause__ is not None: + self.info = ( + "The above exception was the direct cause of the following exception" + ) + elif exc_value.__context__ is not None: + self.info = ( + "During handling of the above exception, another exception occurred" + ) + + self.frames = [] + while tb is not None: + self.frames.append(Frame(exc_type, exc_value, tb)) + tb = tb.tb_next # type: ignore + + def filter_hidden_frames(self) -> None: + # An exception may not have a traceback to filter frames, such + # as one re-raised from ProcessPoolExecutor. + if not self.frames: + return + + new_frames: t.List[Frame] = [] + hidden = False + + for frame in self.frames: + hide = frame.hide + if hide in ("before", "before_and_this"): + new_frames = [] + hidden = False + if hide == "before_and_this": + continue + elif hide in ("reset", "reset_and_this"): + hidden = False + if hide == "reset_and_this": + continue + elif hide in ("after", "after_and_this"): + hidden = True + if hide == "after_and_this": + continue + elif hide or hidden: + continue + new_frames.append(frame) + + # if we only have one frame and that frame is from the codeop + # module, remove it. + if len(new_frames) == 1 and self.frames[0].module == "codeop": + del self.frames[:] + + # if the last frame is missing something went terrible wrong :( + elif self.frames[-1] in new_frames: + self.frames[:] = new_frames + + @property + def exception(self) -> str: + """String representation of the exception.""" + buf = traceback.format_exception_only(self.exc_type, self.exc_value) + rv = "".join(buf).strip() + return _to_str(rv, "utf-8", "replace") + + def render(self, mark_lib: bool = True) -> str: + out = [] + if self.info is not None: + out.append(f'
  • {self.info}:
    ') + for frame in self.frames: + title = f' title="{escape(frame.info)}"' if frame.info else "" + out.append(f"{frame.render(mark_lib=mark_lib)}") + return "\n".join(out) + + def render_text(self) -> str: + out = [] + if self.info is not None: + out.append(f"\n{self.info}:\n") + out.append("Traceback (most recent call last):") + for frame in self.frames: + out.append(frame.render_text()) + out.append(self.exception) + return "\n".join(out) + + +class Frame: + """A single frame in a traceback.""" + + def __init__( + self, + exc_type: t.Type[BaseException], + exc_value: BaseException, + tb: TracebackType, + ) -> None: + self.lineno = tb.tb_lineno + self.function_name = tb.tb_frame.f_code.co_name + self.locals = tb.tb_frame.f_locals + self.globals = tb.tb_frame.f_globals + + fn = inspect.getsourcefile(tb) or inspect.getfile(tb) + if fn[-4:] in (".pyo", ".pyc"): + fn = fn[:-1] + # if it's a file on the file system resolve the real filename. + if os.path.isfile(fn): + fn = os.path.realpath(fn) + self.filename = _to_str(fn, get_filesystem_encoding()) + self.module = self.globals.get("__name__", self.locals.get("__name__")) + self.loader = self.globals.get("__loader__", self.locals.get("__loader__")) + self.code = tb.tb_frame.f_code + + # support for paste's traceback extensions + self.hide = self.locals.get("__traceback_hide__", False) + info = self.locals.get("__traceback_info__") + if info is not None: + info = _to_str(info, "utf-8", "replace") + self.info = info + + def render(self, mark_lib: bool = True) -> str: + """Render a single frame in a traceback.""" + return FRAME_HTML % { + "id": self.id, + "filename": escape(self.filename), + "lineno": self.lineno, + "function_name": escape(self.function_name), + "lines": self.render_line_context(), + "library": "library" if mark_lib and self.is_library else "", + } + + @cached_property + def is_library(self) -> bool: + return any( + self.filename.startswith(os.path.realpath(path)) + for path in sysconfig.get_paths().values() + ) + + def render_text(self) -> str: + return ( + f' File "{self.filename}", line {self.lineno}, in {self.function_name}\n' + f" {self.current_line.strip()}" + ) + + def render_line_context(self) -> str: + before, current, after = self.get_context_lines() + rv = [] + + def render_line(line: str, cls: str) -> None: + line = line.expandtabs().rstrip() + stripped_line = line.strip() + prefix = len(line) - len(stripped_line) + rv.append( + f'
    {" " * prefix}'
    +                f"{escape(stripped_line) if stripped_line else ' '}
    " + ) + + for line in before: + render_line(line, "before") + render_line(current, "current") + for line in after: + render_line(line, "after") + + return "\n".join(rv) + + def get_annotated_lines(self) -> t.List[Line]: + """Helper function that returns lines with extra information.""" + lines = [Line(idx + 1, x) for idx, x in enumerate(self.sourcelines)] + + # find function definition and mark lines + if hasattr(self.code, "co_firstlineno"): + lineno = self.code.co_firstlineno - 1 + while lineno > 0: + if _funcdef_re.match(lines[lineno].code): + break + lineno -= 1 + try: + offset = len(inspect.getblock([f"{x.code}\n" for x in lines[lineno:]])) + except TokenError: + offset = 0 + for line in lines[lineno : lineno + offset]: + line.in_frame = True + + # mark current line + try: + lines[self.lineno - 1].current = True + except IndexError: + pass + + return lines + + def eval(self, code: t.Union[str, CodeType], mode: str = "single") -> t.Any: + """Evaluate code in the context of the frame.""" + if isinstance(code, str): + code = compile(code, "", mode) + return eval(code, self.globals, self.locals) + + @cached_property + def sourcelines(self) -> t.List[str]: + """The sourcecode of the file as list of strings.""" + # get sourcecode from loader or file + source = None + if self.loader is not None: + try: + if hasattr(self.loader, "get_source"): + source = self.loader.get_source(self.module) + elif hasattr(self.loader, "get_source_by_code"): + source = self.loader.get_source_by_code(self.code) + except Exception: + # we munch the exception so that we don't cause troubles + # if the loader is broken. + pass + + if source is None: + try: + with open(self.filename, mode="rb") as f: + source = f.read() + except OSError: + return [] + + # already str? return right away + if isinstance(source, str): + return source.splitlines() + + charset = "utf-8" + if source.startswith(codecs.BOM_UTF8): + source = source[3:] + else: + for idx, match in enumerate(_line_re.finditer(source)): + coding_match = _coding_re.search(match.group()) + if coding_match is not None: + charset = coding_match.group(1).decode("utf-8") + break + if idx > 1: + break + + # on broken cookies we fall back to utf-8 too + charset = _to_str(charset) + try: + codecs.lookup(charset) + except LookupError: + charset = "utf-8" + + return source.decode(charset, "replace").splitlines() + + def get_context_lines( + self, context: int = 5 + ) -> t.Tuple[t.List[str], str, t.List[str]]: + before = self.sourcelines[self.lineno - context - 1 : self.lineno - 1] + past = self.sourcelines[self.lineno : self.lineno + context] + return (before, self.current_line, past) + + @property + def current_line(self) -> str: + try: + return self.sourcelines[self.lineno - 1] + except IndexError: + return "" + + @cached_property + def console(self) -> Console: + return Console(self.globals, self.locals) + + @property + def id(self) -> int: + return id(self) diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/exceptions.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/exceptions.py new file mode 100644 index 0000000..8a31c4d --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/exceptions.py @@ -0,0 +1,944 @@ +"""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 sys +import typing as t +import warnings +from datetime import datetime +from html import escape + +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. + """ + + 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 + + @classmethod + def wrap( + cls, exception: t.Type[BaseException], name: t.Optional[str] = None + ) -> t.Type["HTTPException"]: + """Create an exception that is a subclass of the calling HTTP + exception and the ``exception`` argument. + + The first argument to the class will be passed to the + wrapped ``exception``, the rest to the HTTP exception. If + ``e.args`` is not empty and ``e.show_exception`` is ``True``, + the wrapped exception message is added to the HTTP error + description. + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. Create a subclass manually + instead. + + .. versionchanged:: 0.15.5 + The ``show_exception`` attribute controls whether the + description includes the wrapped exception message. + + .. versionchanged:: 0.15.0 + The description includes the wrapped exception message. + """ + warnings.warn( + "'HTTPException.wrap' is deprecated and will be removed in" + " Werkzeug 2.1. Create a subclass manually instead.", + DeprecationWarning, + stacklevel=2, + ) + + class newcls(cls, exception): # type: ignore + _description = cls.description + show_exception = False + + def __init__( + self, arg: t.Optional[t.Any] = None, *args: t.Any, **kwargs: t.Any + ) -> None: + super().__init__(*args, **kwargs) + + if arg is None: + exception.__init__(self) + else: + exception.__init__(self, arg) + + @property + def description(self) -> str: + if self.show_exception: + return ( + f"{self._description}\n" + f"{exception.__name__}: {exception.__str__(self)}" + ) + + return self._description # type: ignore + + @description.setter + def description(self, value: str) -> None: + self._description = value + + newcls.__module__ = sys._getframe(1).f_globals["__name__"] + name = name or cls.__name__ + exception.__name__ + newcls.__name__ = newcls.__qualname__ = name + return newcls + + @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", "
    ") + return f"

    {description}

    " + + def get_body( + self, + environ: t.Optional["WSGIEnvironment"] = None, + scope: t.Optional[dict] = None, + ) -> str: + """Get the HTML body.""" + return ( + '\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/src/myvenv/lib/python3.10/site-packages/werkzeug/filesystem.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/filesystem.py new file mode 100644 index 0000000..36a3d12 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/filesystem.py @@ -0,0 +1,55 @@ +import codecs +import sys +import typing as t +import warnings + +# We do not trust traditional unixes. +has_likely_buggy_unicode_filesystem = ( + sys.platform.startswith("linux") or "bsd" in sys.platform +) + + +def _is_ascii_encoding(encoding: t.Optional[str]) -> bool: + """Given an encoding this figures out if the encoding is actually ASCII (which + is something we don't actually want in most cases). This is necessary + because ASCII comes under many names such as ANSI_X3.4-1968. + """ + if encoding is None: + return False + try: + return codecs.lookup(encoding).name == "ascii" + except LookupError: + return False + + +class BrokenFilesystemWarning(RuntimeWarning, UnicodeWarning): + """The warning used by Werkzeug to signal a broken filesystem. Will only be + used once per runtime.""" + + +_warned_about_filesystem_encoding = False + + +def get_filesystem_encoding() -> str: + """Returns the filesystem encoding that should be used. Note that this is + different from the Python understanding of the filesystem encoding which + might be deeply flawed. Do not use this value against Python's string APIs + because it might be different. See :ref:`filesystem-encoding` for the exact + behavior. + + The concept of a filesystem encoding in generally is not something you + should rely on. As such if you ever need to use this function except for + writing wrapper code reconsider. + """ + global _warned_about_filesystem_encoding + rv = sys.getfilesystemencoding() + if has_likely_buggy_unicode_filesystem and not rv or _is_ascii_encoding(rv): + if not _warned_about_filesystem_encoding: + warnings.warn( + "Detected a misconfigured UNIX filesystem: Will use" + f" UTF-8 as filesystem encoding instead of {rv!r}", + BrokenFilesystemWarning, + ) + _warned_about_filesystem_encoding = True + return "utf-8" + return rv diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/formparser.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/formparser.py new file mode 100644 index 0000000..6cb758f --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/formparser.py @@ -0,0 +1,495 @@ +import typing as t +import warnings +from functools import update_wrapper +from io import BytesIO +from itertools import chain +from typing import Union + +from . import exceptions +from ._internal import _to_str +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 + + +def parse_multipart_headers(iterable: t.Iterable[bytes]) -> Headers: + """Parses multipart headers from an iterable that yields lines (including + the trailing newline symbol). The iterable has to be newline terminated. + The iterable will stop at the line where the headers ended so it can be + further consumed. + :param iterable: iterable of strings that are newline terminated + """ + warnings.warn( + "'parse_multipart_headers' is deprecated and will be removed in" + " Werkzeug 2.1.", + DeprecationWarning, + stacklevel=2, + ) + result: t.List[t.Tuple[str, str]] = [] + + for b_line in iterable: + line = _to_str(b_line) + line, line_terminated = _line_parse(line) + + if not line_terminated: + raise ValueError("unexpected end of line in multipart header") + + if not line: + break + elif line[0] in " \t" and result: + key, value = result[-1] + result[-1] = (key, f"{value}\n {line[1:]}") + else: + parts = line.split(":", 1) + + if len(parts) == 2: + result.append((parts[0].strip(), parts[1].strip())) + + # we link the list to the headers, no need to create a copy, the + # list was not shared anyways. + return Headers(result) + + +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/src/myvenv/lib/python3.10/site-packages/werkzeug/http.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/http.py new file mode 100644 index 0000000..45799bf --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/http.py @@ -0,0 +1,1393 @@ +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_parse_impl +from ._internal import _cookie_quote +from ._internal import _make_cookie_domain +from ._internal import _to_bytes +from ._internal import _to_str +from ._internal import _wsgi_decoding_dance +from werkzeug._internal import _dt_as_utc + +if t.TYPE_CHECKING: + import typing_extensions as te + 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 + + +@typing.overload +def parse_options_header( + value: t.Optional[str], multiple: "te.Literal[False]" = False +) -> t.Tuple[str, t.Dict[str, str]]: + ... + + +@typing.overload +def parse_options_header( + value: t.Optional[str], multiple: "te.Literal[True]" +) -> t.Tuple[t.Any, ...]: + ... + + +def parse_options_header( + value: t.Optional[str], multiple: bool = False +) -> t.Union[t.Tuple[str, t.Dict[str, str]], t.Tuple[t.Any, ...]]: + """Parse a ``Content-Type`` like header into a tuple with the content + type and the options: + + >>> parse_options_header('text/html; charset=utf8') + ('text/html', {'charset': 'utf8'}) + + This should not be used to parse ``Cache-Control`` like headers that use + a slightly different format. For these headers use the + :func:`parse_dict_header` function. + + .. versionchanged:: 0.15 + :rfc:`2231` parameter continuations are handled. + + .. versionadded:: 0.5 + + :param value: the header to parse. + :param multiple: Whether try to parse and return multiple MIME types + :return: (mimetype, options) or (mimetype, options, mimetype, options, …) + if multiple=True + """ + 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) + + 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) + if multiple is False: + return tuple(result) + value = rest + + return tuple(result) if result else ("", {}) + + +_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() + if not begin_str.isdigit(): + return None + begin = int(begin_str) + if begin < last_end or last_end < 0: + return None + if end_str: + if not end_str.isdigit(): + return None + end = int(end_str) + 1 + 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 + elif length_str.isdigit(): + length = int(length_str) + else: + 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 cookie_date( + expires: t.Optional[t.Union[datetime, date, int, float, struct_time]] = None +) -> str: + """Format a datetime object or timestamp into an :rfc:`2822` date + string for ``Set-Cookie expires``. + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. Use :func:`http_date` instead. + """ + warnings.warn( + "'cookie_date' is deprecated and will be removed in Werkzeug" + " 2.1. Use 'http_date' instead.", + DeprecationWarning, + stacklevel=2, + ) + return http_date(expires) + + +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``. + """ + 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" in environ: + # 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(environ.get("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(environ.get("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(environ.get("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(environ.get("HTTP_IF_MATCH")) + if if_match: + unmodified = not if_match.is_strong(etag) + + return not unmodified + + +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): + header = header.get("HTTP_COOKIE", "") + elif header is None: + header = "" + + # PEP 3333 sends headers through the environ as latin1 decoded + # strings. Encode strings back to bytes for parsing. + if isinstance(header, str): + header = header.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(header): # 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()) + + +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 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/local.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/local.py new file mode 100644 index 0000000..2b22227 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/local.py @@ -0,0 +1,690 @@ +import copy +import math +import operator +import sys +import typing as t +import warnings +from functools import partial +from functools import update_wrapper + +from .wsgi import ClosingIterator + +if t.TYPE_CHECKING: + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + +try: + from greenlet import getcurrent as _get_ident +except ImportError: + from threading import get_ident as _get_ident + + +def get_ident() -> int: + warnings.warn( + "'get_ident' is deprecated and will be removed in Werkzeug" + " 2.1. Use 'greenlet.getcurrent' or 'threading.get_ident' for" + " previous behavior.", + DeprecationWarning, + stacklevel=2, + ) + return _get_ident() # type: ignore + + +class _CannotUseContextVar(Exception): + pass + + +try: + from contextvars import ContextVar + + if "gevent" in sys.modules or "eventlet" in sys.modules: + # Both use greenlet, so first check it has patched + # ContextVars, Greenlet <0.4.17 does not. + import greenlet + + greenlet_patched = getattr(greenlet, "GREENLET_USE_CONTEXT_VARS", False) + + if not greenlet_patched: + # If Gevent is used, check it has patched ContextVars, + # <20.5 does not. + try: + from gevent.monkey import is_object_patched + except ImportError: + # Gevent isn't used, but Greenlet is and hasn't patched + raise _CannotUseContextVar() from None + else: + if is_object_patched("threading", "local") and not is_object_patched( + "contextvars", "ContextVar" + ): + raise _CannotUseContextVar() + + def __release_local__(storage: t.Any) -> None: + # Can remove when support for non-stdlib ContextVars is + # removed, see "Fake" version below. + storage.set({}) + +except (ImportError, _CannotUseContextVar): + + class ContextVar: # type: ignore + """A fake ContextVar based on the previous greenlet/threading + ident function. Used on Python 3.6, eventlet, and old versions + of gevent. + """ + + def __init__(self, _name: str) -> None: + self.storage: t.Dict[int, t.Dict[str, t.Any]] = {} + + def get(self, default: t.Dict[str, t.Any]) -> t.Dict[str, t.Any]: + return self.storage.get(_get_ident(), default) + + def set(self, value: t.Dict[str, t.Any]) -> None: + self.storage[_get_ident()] = value + + def __release_local__(storage: t.Any) -> None: + # Special version to ensure that the storage is cleaned up on + # release. + storage.storage.pop(_get_ident(), None) + + +def release_local(local: t.Union["Local", "LocalStack"]) -> None: + """Releases the contents of the local for the current context. + This makes it possible to use locals without a manager. + + Example:: + + >>> loc = Local() + >>> loc.foo = 42 + >>> release_local(loc) + >>> hasattr(loc, 'foo') + False + + With this function one can release :class:`Local` objects as well + as :class:`LocalStack` objects. However it is not possible to + release data held by proxies that way, one always has to retain + a reference to the underlying local object in order to be able + to release it. + + .. versionadded:: 0.6.1 + """ + local.__release_local__() + + +class Local: + __slots__ = ("_storage",) + + def __init__(self) -> None: + object.__setattr__(self, "_storage", ContextVar("local_storage")) + + @property + def __storage__(self) -> t.Dict[str, t.Any]: + warnings.warn( + "'__storage__' is deprecated and will be removed in Werkzeug 2.1.", + DeprecationWarning, + stacklevel=2, + ) + return self._storage.get({}) # type: ignore + + @property + def __ident_func__(self) -> t.Callable[[], int]: + warnings.warn( + "'__ident_func__' is deprecated and will be removed in" + " Werkzeug 2.1. It should not be used in Python 3.7+.", + DeprecationWarning, + stacklevel=2, + ) + return _get_ident # type: ignore + + @__ident_func__.setter + def __ident_func__(self, func: t.Callable[[], int]) -> None: + warnings.warn( + "'__ident_func__' is deprecated and will be removed in" + " Werkzeug 2.1. Setting it no longer has any effect.", + DeprecationWarning, + stacklevel=2, + ) + + def __iter__(self) -> t.Iterator[t.Tuple[int, t.Any]]: + return iter(self._storage.get({}).items()) + + def __call__(self, proxy: str) -> "LocalProxy": + """Create a proxy for a name.""" + return LocalProxy(self, proxy) + + def __release_local__(self) -> None: + __release_local__(self._storage) + + def __getattr__(self, name: str) -> t.Any: + values = self._storage.get({}) + try: + return values[name] + except KeyError: + raise AttributeError(name) from None + + 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({}).copy() + try: + del values[name] + self._storage.set(values) + except KeyError: + raise AttributeError(name) from None + + +class LocalStack: + """This class works similar to a :class:`Local` but keeps a stack + of objects instead. This is best explained with an example:: + + >>> ls = LocalStack() + >>> ls.push(42) + >>> ls.top + 42 + >>> ls.push(23) + >>> ls.top + 23 + >>> ls.pop() + 23 + >>> ls.top + 42 + + They can be force released by using a :class:`LocalManager` or with + the :func:`release_local` function but the correct way is to pop the + item from the stack after using. When the stack is empty it will + no longer be bound to the current context (and as such released). + + By calling the stack without arguments it returns a proxy that resolves to + the topmost item on the stack. + + .. versionadded:: 0.6.1 + """ + + def __init__(self) -> None: + self._local = Local() + + def __release_local__(self) -> None: + self._local.__release_local__() + + @property + def __ident_func__(self) -> t.Callable[[], int]: + return self._local.__ident_func__ + + @__ident_func__.setter + def __ident_func__(self, value: t.Callable[[], int]) -> None: + object.__setattr__(self._local, "__ident_func__", value) + + def __call__(self) -> "LocalProxy": + def _lookup() -> t.Any: + rv = self.top + if rv is None: + raise RuntimeError("object unbound") + return rv + + return LocalProxy(_lookup) + + def push(self, obj: t.Any) -> t.List[t.Any]: + """Pushes a new item to the stack""" + rv = getattr(self._local, "stack", []).copy() + rv.append(obj) + self._local.stack = rv + return rv + + def pop(self) -> t.Any: + """Removes the topmost item from the stack, will return the + old value or `None` if the stack was already empty. + """ + stack = getattr(self._local, "stack", None) + if stack is None: + return None + elif len(stack) == 1: + release_local(self._local) + return stack[-1] + else: + return stack.pop() + + @property + def top(self) -> t.Any: + """The topmost item on the stack. If the stack is empty, + `None` is returned. + """ + try: + return self._local.stack[-1] + except (AttributeError, IndexError): + return None + + +class LocalManager: + """Local objects cannot manage themselves. For that you need a local + manager. You can pass a local manager multiple locals or add them + later by appending them to `manager.locals`. Every time the manager + cleans up, it will clean up all the data left in the locals for this + context. + + .. versionchanged:: 2.0 + ``ident_func`` is deprecated and will be removed in Werkzeug + 2.1. + + .. versionchanged:: 0.6.1 + The :func:`release_local` function can be used instead of a + manager. + + .. versionchanged:: 0.7 + The ``ident_func`` parameter was added. + """ + + def __init__( + self, + locals: t.Optional[t.Iterable[t.Union[Local, LocalStack]]] = None, + ident_func: None = None, + ) -> None: + if locals is None: + self.locals = [] + elif isinstance(locals, Local): + self.locals = [locals] + else: + self.locals = list(locals) + + if ident_func is not None: + warnings.warn( + "'ident_func' is deprecated and will be removed in" + " Werkzeug 2.1. Setting it no longer has any effect.", + DeprecationWarning, + stacklevel=2, + ) + + @property + def ident_func(self) -> t.Callable[[], int]: + warnings.warn( + "'ident_func' is deprecated and will be removed in Werkzeug 2.1.", + DeprecationWarning, + stacklevel=2, + ) + return _get_ident # type: ignore + + @ident_func.setter + def ident_func(self, func: t.Callable[[], int]) -> None: + warnings.warn( + "'ident_func' is deprecated and will be removedin Werkzeug" + " 2.1. Setting it no longer has any effect.", + DeprecationWarning, + stacklevel=2, + ) + + def get_ident(self) -> int: + """Return the context identifier the local objects use internally for + this context. You cannot override this method to change the behavior + but use it to link other context local objects (such as SQLAlchemy's + scoped sessions) to the Werkzeug locals. + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. + + .. versionchanged:: 0.7 + You can pass a different ident function to the local manager that + will then be propagated to all the locals passed to the + constructor. + """ + warnings.warn( + "'get_ident' is deprecated and will be removed in Werkzeug 2.1.", + DeprecationWarning, + stacklevel=2, + ) + return self.ident_func() + + def cleanup(self) -> None: + """Manually clean up the data in the locals for this context. Call + this at the end of the request or use `make_middleware()`. + """ + for local in self.locals: + release_local(local) + + def make_middleware(self, app: "WSGIApplication") -> "WSGIApplication": + """Wrap a WSGI application so that cleaning up happens after + request end. + """ + + 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 `make_middleware` but for decorating functions. + + Example usage:: + + @manager.middleware + def application(environ, start_response): + ... + + The difference to `make_middleware` is that the function passed + will have all the arguments copied from the inner application + (name, docstring, module). + """ + 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() + except RuntimeError: + if self.fallback is None: + raise + + fallback = self.fallback.__get__(instance, owner) # type: ignore + + 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) + + +class LocalProxy: + """A proxy to the object bound to a :class:`Local`. All operations + on the proxy are forwarded to the bound object. If no object is + bound, a :exc:`RuntimeError` is raised. + + .. code-block:: python + + from werkzeug.local import Local + l = Local() + + # a proxy to whatever l.user is set to + user = l("user") + + from werkzeug.local import LocalStack + _request_stack = LocalStack() + + # a proxy to _request_stack.top + request = _request_stack() + + # a proxy to the session attribute of the request proxy + session = LocalProxy(lambda: request.session) + + ``__repr__`` and ``__class__`` are forwarded, 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 + + :param local: The :class:`Local` or callable that provides the + proxied object. + :param name: The attribute name to look up on a :class:`Local`. Not + used if a callable is given. + + .. 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__ = ("__local", "__name", "__wrapped__") + + def __init__( + self, + local: t.Union["Local", t.Callable[[], t.Any]], + name: t.Optional[str] = None, + ) -> None: + object.__setattr__(self, "_LocalProxy__local", local) + object.__setattr__(self, "_LocalProxy__name", name) + + if callable(local) and not hasattr(local, "__release_local__"): + # "local" is a callable that is not an instance of Local or + # LocalManager: mark it as a wrapped function. + object.__setattr__(self, "__wrapped__", local) + + def _get_current_object(self) -> t.Any: + """Return the current object. This is useful if you want the real + object behind the proxy at a time for performance reasons or because + you want to pass the object into a different context. + """ + if not hasattr(self.__local, "__release_local__"): # type: ignore + return self.__local() # type: ignore + + try: + return getattr(self.__local, self.__name) # type: ignore + except AttributeError: + name = self.__name # type: ignore + raise RuntimeError(f"no object bound to {name}") from None + + __doc__ = _ProxyLookup( # type: ignore + class_value=__doc__, fallback=lambda self: type(self).__doc__, 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/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__init__.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__init__.py new file mode 100644 index 0000000..6ddcf7f --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/__init__.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..808b4f30ed57f277a2e1ba161d8574bda85b8b1d GIT binary patch literal 707 zcmYjPv2NQi5S6pkAdr9H8lV+xbQ4meor(?(3b;UkF7!z}i%cYv6;HC=Kk8rf8#-pq z+^timp6DR;0V3|+=uPht#C*oD}mCz-vTrOb)*?Rr~^ zo2$jc3$0nW)<25jf}cZP{@y9eR;#-)k@KiF;7uJ4>hqDMc(wU9x|=|lRDYb%PpWgZ xikW*;u3oF;2wz2L?xE#9`={Ti{!gs5cHWWJWjsDCulr!e4%hRuOtXe%@ef_9!T2rzS7zy08z`!pq3z>A{hX8C+M3r4jZmbBV+9E`O#c*dRuCq7K z3?(zAp5o{JfuMl%n19jV(8qo4Q~rX{r2WpUR-_YmiJhI9Gw1%DGc2~ZLkG`4|MkK2 zCT9Pp#pdH<@hM(?fI&DDN4UaE-H9i?XTEwLD?bgg)}-YUCBVErY1?@V^UkE>I*%OD z7M+)l=zQ%>y22Yf{Vx9^aGY?jEYl?BCMk0EAkif^@m#9#lea!$crs5k%Mu|{dCrw& zv69?K%{bFZews@5m+_-R#y5nTIX6r+k~K3$m@QJ1lsH@%==vE86cmfxNWm=UY$lb= z4g1s6<>`>p>XqvAD=Gm@HrLj3mLTbCnp_08_@bDaZU&vJL-s**Vlnwk#HG&d(&{ z;grW;%3QF$V;GGuXERkmHKrsE6PD!cF+bzuSS6)lwKoMkhUrWd3sM>43@xXsIM;AU z!Ag8^HfKscUr22Y6G`Jr3ClF8$}Asv&ZHV3xN@x@9$f|X;N;0?*1pGMHcQ~HHAByf zMJm`-GAlr^S)p)h8B&z6trGz)w}-q;ZX;$kbxpk9NC=qf2$UsTmATWjOR`6ow2B>q92BbIV)8m7BOLc*P7%J2(fSFP5}piZ_5?XH~N)*MKsxnih4P4Hyy~ zUO}#jFA!|=DS1rUV?vf`u>|XRf^-54vgAP4Wr@|&cSA}7S*i_cIKH&17PJP2NR*6C zx@6PkPu&7A1_QM zy?=K<hBp zc*_B8TkO0HCf963yiwg;H^4Ox`D52{_KR$q+q^_1X@~t$FPk0KfuMt#&`jw&Cv zDj#{Q+O@E%t)y9~Jf_X&p}B{5AFsZNVdbuz$XR)1J8>`r0>;jF?or=UZBSJQL*K6g zEz{Y0=Q~GT1L1W#oEMoKK3h;HmcucsW?H-$9xu(j$cN+Si{z-lH8#waXEHwXfMM<8RD7p{b8n>*|Ztb{V z{pvw;3#v7|2F=;31I<(biWsUL6tpstx~v;Tv3MguR1$R32I%jYtlU@jpTW1@g)h8| zK=>>F%u&Bt`77s{i`jehUHP}1i`MfGSNK<{t za;yX&a$8nMOL&-fR-Kjq9<++q$Kb=)#TO@5-q-a1qJ1>kI^H`uhz^hb@OkCDc8A}i zketc2@&41psx|B2KN4c9SLZEY{$$rd3J;l;H= zd7o^dYnccM$|g4p^rs}}X;hz$a-K<>|9a?=9ONcO=Zd1=Vx@nHq2~u~*9+ay_1qiY zj@x~GqucX(ZWlZMH)pjBwFUlukA#x0D5}CJ%5cY|H19>x^94^YDV-=1MT~9NRNc=@ zx`cRI1rL(gRK7M!ZCmpWjZ}P^%BnS80+H%n>~8o#XjbHiYGLT()weNpoxt^a!4ID2 z{rHaW{on=Rf4r{edjF-j>+SqlpWjly!0D=OmL)1uy-$nnlP``RM*9a3_y2f!^k}jZ sfhhG{iov-)O)T(ixmsLWF>kY{>V8~1{yWODro;tKm$eZ{`n}`-4<-&bT>t<8 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/http_proxy.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/http_proxy.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..90a0c00231a9420959f41e367909087e14b8f3a9 GIT binary patch literal 6881 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 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/lint.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/lint.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6ab4b299d4975d1540e81e1fe71c3411b28e8957 GIT binary patch literal 12748 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 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/profiler.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/profiler.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c698126f0de2d826f84dd8502d32edea398282db GIT binary patch literal 4998 zcmb_g-EZ606(=c*qG|avPTRBtcDD{_g~gJ)V%VytMY7aQjUkR#rwA%wpeWuen+`>) zmsfV=$WI9n_o3S#&d<(7kIDX#R~ zmTMY^F5c{TrsuUh(|BMc3$`Ij)V4M zYf-l=XfL&vOyiEhT|V>F;4@FG)-t!YjhYv{V;Y8ctKW~KFi=sNuq~N(qgY7qy-P07 zyT2P{te5gZELdNr`w~iiU_w#zYYAGATYAh)l7ANbO==cujC< zw!`sW?J>hT)7--#VY?#kGw@DS)E%-;s#Giz5kAaVl(1nskSt8O@bq5205b&3;`AU& zb{J0&##4fGwd$T%ud`sF(l8FPtl2!%^X{4Cp4SZ1{!m6cyQ;~4wYK&fwiU#&P?^_+ zc|?+lCi~s?2di(d-j0JoCcJ;bzs6?G%*)#;f)_B`Q=SyAnlt{E7gCD7>cs&M%nx4ZLvo-aHtx90gGU*gOB3ZK&}7p@sy zhp+IfPwmzsw*i@#^5wCP^4xU6m5O0JkU<|%AT8OH=~nu%#p2qsvb7F!*m-{dkaY%xmU=$O;csR&Z+KUdstTSYN zAej)~Zcpa<-Bk7h)ozo>T98PQ83G2QVCr=!i71R?Vphym;5E=}nmwU*n`FNFn2iot z&4&EeP2+Khbt4gTaNQ50IOxQpSxCGJ5478liA~CnV53z8w3w*HivD-mo%Q?I+19;n zP@%%Q=09HA57h393#pf-lD#3*RK3Bn-E6TNW++^Db&a(tH6}UQFVXw1r zyt|NNoB*L+AP9&g0MOzAL}kz)a#Q2U(Dub z@&R+~y-Oy%iGf*J_hTBv{xYcy$N#lkPnY^6+)!002O!8y>vCek&$K&kOtgm&CdRhH3EzmF8Re1@9Mu})_!~C7}QDaL-Kx6x}LA04Fku`clAZ@=9N1a9y9dFm) zT5Dv;h^ze|d>HIt&Llz_=MmBvODpUBA(Zl?BvQVA7u#nfmowv-#m_SjU)vg&%jdOF zeX=62j1#_euq>ZP-a-O|WpqI(ZFGhukjX`w(@g5i-bY=&V|;G$m1ov7yQ@DPp3Z!3 z@T<>^XD0eeU7KpZr`4m9GM*SmwlYu5Q{$*SvQMm0>C{B=@0^s5tyA;JDaJW@G3C3*r4#4a#7sANjr#T~$0n~_GeA*Kp5U|L)I6EtGu%71`gi&4 zsKTo&M!}WOePJKD%G;a8Zs0v~Ppu;tQdH4`6zH4N`+cS6N49>O|H3+&8O`i1;BE0w z_^eS&oZ54I@e2zp%#&q&sw{zzhmqxx_oek0>wFw5ui$NEvhquVU%4>u?3h%kZeB1i znU!pgFE%4v1~~@U0eI_430oR_fVEsgH_CDcxE2Yol_=x_HOTVHt_V2tT<(fTArR3` z5!!PTU;3St59Lp=xIpPOwDOnnK^5*Iozs~&<@gQ;GZLf<7#-fY6hM?Me7}AJxjl%p z_v=5vN-ly;i2LjUY7B~Mt>kaffM=m7JOubd*Y8+c9h;8zXLUeQMi6vhh87Jja z`oM%4=&qGEHA3@p7^nDraU_{6H&t$jL8fv?JVM#bVVEEbl#=pw4A;z-3)A_CFj=$Z z&(S4cBl0sMuMp8utnK5-L4wI$^kx+0wplgp@4b>|(ev<^Kguu#kAGn~0_@}UKYX&j zec!*ke*dF;AGBt+Zr%UL-`M={-Zy3=H|x1g_2UlBHE#a-X3fr>q9o02%ESoQqHdJ* z{a!P5COX_&{XbuTmrV&UHx3;Vu*q`MD}ZNde{R;UO2VoZqg8>1gofPSOQS@-gn`_p z4l3Q`%k=6L)p}m0(gXQe3RDcC$gMP!4NPcxe9-F`m6s%7NXq#w@4Oz9E5xU)%cZ=u zBUB4#$ywL9Ki# zKs0X+5TxEB4*m#s8G+d@Em|wKGvk^bepS=6h&q;IzEY&*Zxj&9Rq*I74Ui2BLg}F@I+`UnlosK;tV<5KS&bcQ2s-|Tvf-XWO Mr&L9&YA%=l2j`ifjQ{`u literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/proxy_fix.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/proxy_fix.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1b9961cb8528cba98461423d611d99987b49a14b GIT binary patch literal 6209 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 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/shared_data.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/__pycache__/shared_data.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..841b379a3b9c726a4b5efe91e8943eecbd8c8a5a GIT binary patch literal 9925 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 OS8eU0nomcj^#1`CmP-%- literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/dispatcher.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/dispatcher.py new file mode 100644 index 0000000..ace1c75 --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/http_proxy.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/http_proxy.py new file mode 100644 index 0000000..1cde458 --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/lint.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/lint.py new file mode 100644 index 0000000..c74703b --- /dev/null +++ b/src/myvenv/lib/python3.10/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], None], 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.isdigit(): + 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/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/profiler.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/profiler.py new file mode 100644 index 0000000..200dae0 --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/proxy_fix.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/proxy_fix.py new file mode 100644 index 0000000..4cef7cc --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/shared_data.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/shared_data.py new file mode 100644 index 0000000..62da672 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/middleware/shared_data.py @@ -0,0 +1,320 @@ +""" +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 ..filesystem import get_filesystem_encoding +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) + + if hasattr(provider, "get_resource_reader"): + # Python 3 + 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), + ), + ) + + else: + # Python 3.6 + package_filename = provider.get_filename(package) # type: ignore + is_filesystem = os.path.exists(package_filename) + root = os.path.join(os.path.dirname(package_filename), package_path) + + def loader( + path: t.Optional[str], + ) -> t.Tuple[t.Optional[str], t.Optional[_TOpener]]: + if path is None: + return None, None + + path = safe_join(root, path) + + if path is None: + return None, None + + basename = posixpath.basename(path) + + if is_filesystem: + if not os.path.isfile(path): + return None, None + + return basename, self._opener(path) + + try: + data = provider.get_data(path) # type: ignore + except OSError: + return None, None + + return basename, lambda: (BytesIO(data), load_time, len(data)) + + 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: + if not isinstance(real_filename, bytes): + real_filename = real_filename.encode( # type: ignore + get_filesystem_encoding() + ) + + timestamp = mtime.timestamp() + checksum = adler32(real_filename) & 0xFFFFFFFF # type: ignore + 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/src/myvenv/lib/python3.10/site-packages/werkzeug/py.typed b/src/myvenv/lib/python3.10/site-packages/werkzeug/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/routing.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/routing.py new file mode 100644 index 0000000..937b42b --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/routing.py @@ -0,0 +1,2342 @@ +"""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. +""" +import ast +import difflib +import posixpath +import re +import typing +import typing as t +import uuid +import warnings +from pprint import pformat +from string import Template +from threading import Lock +from types import CodeType + +from ._internal import _encode_idna +from ._internal import _get_environ +from ._internal import _to_bytes +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 BadRequest +from .exceptions import HTTPException +from .exceptions import MethodNotAllowed +from .exceptions import NotFound +from .urls import _fast_url_quote +from .urls import url_encode +from .urls import url_join +from .urls import url_quote +from .urls import url_unquote +from .utils import cached_property +from .utils import redirect +from .wsgi import get_host + +if t.TYPE_CHECKING: + import typing_extensions as te + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + from .wrappers.request import Request + from .wrappers.response import Response + +_rule_re = re.compile( + r""" + (?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 _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 + + +def parse_rule(rule: str) -> t.Iterator[t.Tuple[t.Optional[str], t.Optional[str], str]]: + """Parse a rule and return it as generator. Each iteration yields tuples + in the form ``(converter, arguments, variable)``. If the converter is + `None` it's a static url part, otherwise it's a dynamic one. + + :internal: + """ + pos = 0 + end = len(rule) + do_match = _rule_re.match + used_names = set() + while pos < end: + m = do_match(rule, pos) + if m is None: + break + data = m.groupdict() + if data["static"]: + yield None, None, data["static"] + variable = data["variable"] + converter = data["converter"] or "default" + if variable in used_names: + raise ValueError(f"variable name {variable!r} used twice.") + used_names.add(variable) + yield converter, data["args"] or None, variable + pos = m.end() + if pos < end: + remaining = rule[pos:] + if ">" in remaining or "<" in remaining: + raise ValueError(f"malformed url rule: {rule!r}") + yield None, None, remaining + + +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]) -> None: + super().__init__() + self.matched_values = matched_values + + +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 ValidationError(ValueError): + """Validation error. If a rule converter raises this exception the rule + does not match the current URL and the next URL is tried. + """ + + +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: + q = '?' + params = self._encode_query_vars(kwargs) +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`` he 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. + + .. 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.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._trace: t.List[t.Tuple[bool, str]] = [] + + 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 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._trace = [] + self._converters: t.Dict[str, "BaseConverter"] = {} + self._static_weights: t.List[t.Tuple[int, int]] = [] + self._argument_weights: t.List[int] = [] + regex_parts = [] + + def _build_regex(rule: str) -> None: + index = 0 + for converter, arguments, variable in parse_rule(rule): + if converter is None: + for match in re.finditer(r"/+|[^/]+", variable): + part = match.group(0) + if part.startswith("/"): + if self.merge_slashes: + regex_parts.append(r"/+?") + self._trace.append((False, "/")) + else: + regex_parts.append(part) + self._trace.append((False, part)) + continue + self._trace.append((False, part)) + regex_parts.append(re.escape(part)) + if part: + self._static_weights.append((index, -len(part))) + else: + if arguments: + c_args, c_kwargs = parse_converter_args(arguments) + else: + c_args = () + c_kwargs = {} + convobj = self.get_converter(variable, converter, c_args, c_kwargs) + regex_parts.append(f"(?P<{variable}>{convobj.regex})") + self._converters[variable] = convobj + self._trace.append((True, variable)) + self._argument_weights.append(convobj.weight) + self.arguments.add(str(variable)) + index = index + 1 + + _build_regex(domain_rule) + regex_parts.append("\\|") + self._trace.append((False, "|")) + _build_regex(self.rule if self.is_leaf else self.rule.rstrip("/")) + if not self.is_leaf: + self._trace.append((False, "/")) + + self._build: t.Callable[..., t.Tuple[str, str]] + self._build = self._compile_builder(False).__get__(self, None) # type: ignore + self._build_unknown: t.Callable[..., t.Tuple[str, str]] + self._build_unknown = self._compile_builder(True).__get__( # type: ignore + self, None + ) + + if self.build_only: + return + + if not (self.is_leaf and self.strict_slashes): + reps = "*" if self.merge_slashes else "?" + tail = f"(?/{reps})" + else: + tail = "" + + regex = f"^{''.join(regex_parts)}{tail}$" + self._regex = re.compile(regex) + + def match( + self, path: str, method: t.Optional[str] = None + ) -> t.Optional[t.MutableMapping[str, t.Any]]: + """Check if the rule matches a given path. Path is a string in the + form ``"subdomain|/path"`` and is assembled by the map. If + the map is doing host matching the subdomain part will be the host + instead. + + If the rule matches a dict with the converted values is returned, + otherwise the return value is `None`. + + :internal: + """ + if not self.build_only: + require_redirect = False + + m = self._regex.search(path) + if m is not None: + groups = m.groupdict() + # we have a folder like part of the url without a trailing + # slash and strict slashes enabled. raise an exception that + # tells the map to redirect to the same url but with a + # trailing slash + if ( + self.strict_slashes + and not self.is_leaf + and not groups.pop("__suffix__") + and ( + method is None or self.methods is None or method in self.methods + ) + ): + path += "/" + require_redirect = True + # if we are not in strict slashes mode we have to remove + # a __suffix__ + elif not self.strict_slashes: + del groups["__suffix__"] + + result = {} + for name, value in groups.items(): + try: + value = self._converters[name].to_python(value) + except ValidationError: + return None + result[str(name)] = value + if self.defaults: + result.update(self.defaults) + + if self.merge_slashes: + new_path = "|".join(self.build(result, False)) # type: ignore + if path.endswith("/") and not new_path.endswith("/"): + new_path += "/" + if new_path.count("/") < path.count("/"): + # The URL will be encoded when MapAdapter.match + # handles the RequestPath raised below. Decode + # the URL here to avoid a double encoding. + path = url_unquote(new_path) + require_redirect = True + + if require_redirect: + path = path.split("|", 1)[1] + raise RequestPath(path) + + if self.alias and self.map.redirect_defaults: + raise RequestAliasRedirect(result) + + return result + + return 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 "col_offset" in node._attributes: + node.col_offset = 0 + + 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 match_compare_key( + self, + ) -> t.Tuple[bool, int, t.Iterable[t.Tuple[int, int]], int, t.Iterable[int]]: + """The match compare key for sorting. + + Current implementation: + + 1. rules without any arguments come first for performance + reasons only as we expect them to match faster and some + common ones usually don't have any arguments (index pages etc.) + 2. rules with more static parts come first so the second argument + is the negative length of the number of the static weights. + 3. we order by static weights, which is a combination of index + and length + 4. The more complex rules come first so the next argument is the + negative length of the number of argument weights. + 5. lastly we order by the actual argument weights. + + :internal: + """ + return ( + bool(self.arguments), + -len(self._static_weights), + self._static_weights, + -len(self._argument_weights), + self._argument_weights, + ) + + 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}>" + + +class BaseConverter: + """Base class for all converters.""" + + regex = "[^/]+" + weight = 100 + + def __init__(self, map: "Map", *args: t.Any, **kwargs: t.Any) -> 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. + """ + + 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. + """ + + def __init__(self, map: "Map", *items: str) -> None: + super().__init__(map) + self.regex = f"(?:{'|'.join([re.escape(x) for x in items])})" + + +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 + + +class NumberConverter(BaseConverter): + """Baseclass for `IntegerConverter` and `FloatConverter`. + + :internal: + """ + + weight = 50 + num_convert: t.Callable = int + + 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+" + + +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 + + 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}" + ) + + 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, +} + + +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._rules: t.List[Rule] = [] + 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 + + 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) + self._rules.append(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._rules.sort(key=lambda x: x.match_compare_key()) + 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 + + @typing.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]]: + ... + + @typing.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 + + require_redirect = False + + domain_part = self.server_name if self.map.host_matching else self.subdomain + path_part = f"/{path_info.lstrip('/')}" if path_info else "" + path = f"{domain_part}|{path_part}" + + have_match_for = set() + websocket_mismatch = False + + for rule in self.map._rules: + try: + rv = rule.match(path, method) + 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( + path, rule.endpoint, e.matched_values, method, query_args + ) + ) from None + if rv is None: + continue + if rule.methods is not None and method not in rule.methods: + have_match_for.update(rule.methods) + continue + + if rule.websocket != websocket: + websocket_mismatch = True + continue + + 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)] # type: ignore + 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 require_redirect: + raise RequestRedirect( + self.make_redirect_url( + url_quote(path_info, self.map.charset, safe="/:|+"), query_args + ) + ) + + if return_rule: + return rule, rv + else: + return rule.endpoint, rv + + if have_match_for: + raise MethodNotAllowed(valid_methods=list(have_match_for)) + + if websocket_mismatch: + raise WebsocketMismatch() + + raise NotFound() + + 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: + temp_values: t.Dict[str, t.Union[t.List[t.Any], t.Any]] = {} + always_list = isinstance(values, MultiDict) + key: str + value: t.Optional[t.Union[t.List[t.Any], t.Any]] + + # For MultiDict, dict.items(values) is like values.lists() + # without the call or list coercion overhead. + for key, value in dict.items(values): # type: ignore + if value is None: + continue + + if always_list or isinstance(value, (list, tuple)): + value = [v for v in value if v is not None] + + if not value: + continue + + if len(value) == 1: + value = value[0] + + temp_values[key] = value + + values = temp_values + 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/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/__init__.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/__pycache__/__init__.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..49036bf7d3ebf5788221a96adfbb3c32b94d3bfe GIT binary patch literal 195 zcmd1j<>g`kf&-TflR)%i5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;x_oenx(7s(w~! zaY<%gs(x@{UP@Aag?>O~Nk)F2esE!FreA(ZYO#K9Wm#%onSM@Yl70bL&REaTK)*P% zBvrQ{F*!Ri9jK-}wJ5tPwKQG7I5Dp{GhaVGJ~J<~BtBlRpz;=nO>TZlX-=vg$o^s` IAi=@_0HX0T#Q*>R literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/__pycache__/multipart.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/__pycache__/multipart.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3817a016adb37e5a72328a126503b6947acd06ac GIT binary patch literal 6469 zcmai2&2t>bb)V_^*xA_+f*`oyH;14gY8`>F>^QDal1++SS+vL{O+s<9qB0(AH-KI4 z&Mv!WNdj3^WI?&4ELRT6$>l2G$Wspf2Ykyt<%2!fR8pnfTs+vN3a$KJ&n~b4$Yi&s z=k@H#eEJI$*kgPK*cmai zWo?;_;}ewQyaGyPM5#iU5f`@dN(7L(EC

    XfVAPmO8b^B2Mbhtkes` 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 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/__pycache__/request.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/__pycache__/request.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f80e666960334e575a155edabf6c5322d0d5eefc GIT binary patch literal 17119 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 T4PCCH$2mUz!vBw@4;=l!79Y=5 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/__pycache__/utils.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0f93dbb135e6c9c5bbbe57b10da6b25944e86e33 GIT binary patch literal 3934 zcmcIn&2Jn@74NF<8TX9GcGk&~4;EB}%_ak8CcBA57%d5_EGsOKiQ+^EOK7G&RpaTn zr+ZRWZO7IaAsmkU1*?@3i3|S)2mS(%eOifA&TvYy8-A~P#vfTEPPEl;Ue|l|s_K3G z>N#6jsC#(+_Ky!YKRx4l|D=zT&jLPvhSz)vB0b3xZ-YrL{e+MF4WD`7gCrPLHY$#< zB-PQ}#+>7;;KPj&{G6)EP_ajKRlDfPnwlR}WnIoc4K^AzR%7ylY(QfH8VgQi(Q)k2 zqN+J=>7qB_7d^~fno67{XR9`-%QNzwr<;dt-au&O;$9zD(z=dbz_-E_+D67{anX(@8?=)8UuBFb#2y-b&RiC zu9NQLJhQ3@hncZyG*U&w>fBf*yGd+pQPs-kI_=W}vu6%W4ewpN=IrI$t zhg>%%Y>OSh?UqU3@w#zey(`S4zuzKM>)tLbeCqw~ z#|ObAcoxX&bEa=i0y!tcKf#>`fvg==QZCs+#aRkqsR~Q;&eAVumJqY^2(ckZN(N+Urp&H?t@0dwX`6rS0{{dAx?SH0{yej!Jjh zNxaz}JK2rahu7OCw(3XYsJ|U;L1$O#?R}MRwM~@bi0$0QiD`}Zih4KA^ay_4R~N9T zse**;3=8@G_bI^L*mS4iXnmYy{U|ZFTgP(>*3$Esvi9I#bf8wVTGV3$r`jm(tHL){ z7nRLDY_n)QOk*lMS7$}Nj1h&X2vsT#am~5X(;-ahC6JB9S0n}zY4@=e zBkzQ(Y-Le7(^`KpjExw?8k(-MjZ^ORPI#=>b5$GLt45@#&aqZTrFMlhQ&)1mUg^_b zPrzDklx#W7a2s%yoTbU0=x3=#3A+`>nMR!tsMKTQjL3K}P#T6Ik4h!VOBrb?oc8P_ zW1ZQopC!{1{CaE&1(IZMg&-jw?2!SoGW7tqG())@$-d=Q>kRU=-zkrITr@p_1%-}c zqeN8dsV7kT{j4He_*8B|(>iq(;pEf9kdICSX_a~WPQH*gHb-7wo32rY<9~;sLwC!`s3Q-vkY-n@BJ3Mwupg}-aee$csj^TvzUknLA!_hSDHWj$5KY>}p~&%>Sr zAx%KitmsQL@NFXR5%~@X*24U^aWLFcwo8IrP%+;H2`+_zwGe*|z6^+4WXlA3ybk0C z)O|qqu8_T&&NADjz!ia`4dj>J>tYe)eV<@$_R!5iuYt1B&L;Awil_$rkFr@M*x#vEi(btw-cjXSRve@ zQb%85s0e{Nq>9c+qt&4nB<&|TG{MZ4Izmh(Xko-0FtvJrb;V7HFbLLUWO@`Gquul( z1-zoG>X*=q(h(1VF;f&e&TaIsriEUXT3U3rJ=bw%DR2#2LV{)Dll8l+tN$N-DS?Gj z?-V-iMg|9xaCz1e>*{FNvphWwR7WY;5%+M{12K-!I2xmQ>PH0ECT@;`mFOS}L8 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/multipart.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/multipart.py new file mode 100644 index 0000000..2d54422 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/multipart.py @@ -0,0 +1,260 @@ +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) + + +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, + ) + + 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) + 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) + + elif self.state == State.PART: + match = BLANK_LINE_RE.search(self.buffer) + 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 + + 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/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/request.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/request.py new file mode 100644 index 0000000..adafc26 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/request.py @@ -0,0 +1,548 @@ +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_cookie +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 ..useragents import _UserAgent as _DeprecatedUserAgent +from ..utils import cached_property +from ..utils import header_property +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] = _DeprecatedUserAgent + """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/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/response.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/response.py new file mode 100644 index 0000000..82817e8 --- /dev/null +++ b/src/myvenv/lib/python3.10/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 = "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") + + if len(split_status) > 1: + if split_status[0].isdigit(): + # code and message + return status, int(split_status[0]) + + # multi-word message + return f"0 {status}", 0 + + if split_status[0].isdigit(): + # code only + status_code = int(split_status[0]) + + try: + status = f"{status_code} {HTTP_STATUS_CODES[status_code].upper()}" + except KeyError: + status = f"{status_code} UNKNOWN" + + return status, status_code + + # one-word message + return f"0 {status}", 0 + + 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 + elif value.isdigit(): + return datetime.now(timezone.utc) + timedelta(seconds=int(value)) + return parse_date(value) + + @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/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/utils.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/utils.py new file mode 100644 index 0000000..1b4d892 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/sansio/utils.py @@ -0,0 +1,142 @@ +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)) diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/security.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/security.py new file mode 100644 index 0000000..e23040a --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/security.py @@ -0,0 +1,247 @@ +import hashlib +import hmac +import os +import posixpath +import secrets +import typing as t +import warnings + +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 pbkdf2_hex( + data: t.Union[str, bytes], + salt: t.Union[str, bytes], + iterations: int = DEFAULT_PBKDF2_ITERATIONS, + keylen: t.Optional[int] = None, + hashfunc: t.Optional[t.Union[str, t.Callable]] = None, +) -> str: + """Like :func:`pbkdf2_bin`, but returns a hex-encoded string. + + :param data: the data to derive. + :param salt: the salt for the derivation. + :param iterations: the number of iterations. + :param keylen: the length of the resulting key. If not provided, + the digest size will be used. + :param hashfunc: the hash function to use. This can either be the + string name of a known hash function, or a function + from the hashlib module. Defaults to sha256. + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. Use :func:`hashlib.pbkdf2_hmac` + instead. + + .. versionadded:: 0.9 + """ + warnings.warn( + "'pbkdf2_hex' is deprecated and will be removed in Werkzeug" + " 2.1. Use 'hashlib.pbkdf2_hmac().hex()' instead.", + DeprecationWarning, + stacklevel=2, + ) + return pbkdf2_bin(data, salt, iterations, keylen, hashfunc).hex() + + +def pbkdf2_bin( + data: t.Union[str, bytes], + salt: t.Union[str, bytes], + iterations: int = DEFAULT_PBKDF2_ITERATIONS, + keylen: t.Optional[int] = None, + hashfunc: t.Optional[t.Union[str, t.Callable]] = None, +) -> bytes: + """Returns a binary digest for the PBKDF2 hash algorithm of `data` + with the given `salt`. It iterates `iterations` times and produces a + key of `keylen` bytes. By default, SHA-256 is used as hash function; + a different hashlib `hashfunc` can be provided. + + :param data: the data to derive. + :param salt: the salt for the derivation. + :param iterations: the number of iterations. + :param keylen: the length of the resulting key. If not provided + the digest size will be used. + :param hashfunc: the hash function to use. This can either be the + string name of a known hash function or a function + from the hashlib module. Defaults to sha256. + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. Use :func:`hashlib.pbkdf2_hmac` + instead. + + .. versionadded:: 0.9 + """ + warnings.warn( + "'pbkdf2_bin' is deprecated and will be removed in Werkzeug" + " 2.1. Use 'hashlib.pbkdf2_hmac()' instead.", + DeprecationWarning, + stacklevel=2, + ) + + if isinstance(data, str): + data = data.encode("utf8") + + if isinstance(salt, str): + salt = salt.encode("utf8") + + if not hashfunc: + hash_name = "sha256" + elif callable(hashfunc): + hash_name = hashfunc().name + else: + hash_name = hashfunc + + return hashlib.pbkdf2_hmac(hash_name, data, salt, iterations, keylen) + + +def safe_str_cmp(a: str, b: str) -> bool: + """This function compares strings in somewhat constant time. This + requires that the length of at least one string is known in advance. + + Returns `True` if the two strings are equal, or `False` if they are not. + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. Use + :func:`hmac.compare_digest` instead. + + .. versionadded:: 0.7 + """ + warnings.warn( + "'safe_str_cmp' is deprecated and will be removed in Werkzeug" + " 2.1. Use 'hmac.compare_digest' instead.", + DeprecationWarning, + stacklevel=2, + ) + + if isinstance(a, str): + a = a.encode("utf-8") # type: ignore + + if isinstance(b, str): + b = b.encode("utf-8") # type: ignore + + return hmac.compare_digest(a, b) + + +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``. + """ + 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/src/myvenv/lib/python3.10/site-packages/werkzeug/serving.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/serving.py new file mode 100644 index 0000000..80e4192 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/serving.py @@ -0,0 +1,1088 @@ +"""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 io +import os +import platform +import signal +import socket +import socketserver +import sys +import typing as t +import warnings +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 +can_open_by_fd = not platform.system() == "Windows" and hasattr(socket, "fromfd") + +_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) + + def shutdown_server() -> None: + warnings.warn( + "The 'environ['werkzeug.server.shutdown']' function is" + " deprecated and will be removed in Werkzeug 2.1.", + stacklevel=2, + ) + self.server.shutdown_signal = True + + 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.server.shutdown": shutdown_server, + "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 + + def write(data: bytes) -> None: + nonlocal status_sent, headers_sent + 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) + key = key.lower() + header_keys.add(key) + if not ( + "content-length" in header_keys + or environ["REQUEST_METHOD"] == "HEAD" + or code < 200 + or code in (204, 304) + ): + self.close_connection = True + self.send_header("Connection", "close") + if "server" not in header_keys: + self.send_header("Server", self.version_string()) + if "date" not in header_keys: + self.send_header("Date", self.date_time_string()) + self.end_headers() + + assert isinstance(data, bytes), "applications must write bytes" + self.wfile.write(data) + 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"") + 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: + if self.server.passthrough_errors: + raise + from .debug.tbtools import get_current_traceback + + traceback = get_current_traceback(ignore_system_exceptions=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 + self.server.log("error", "Error on request:\n%s", traceback.plaintext) + + def handle(self) -> None: + """Handles a request ignoring dropped connections.""" + try: + BaseHTTPRequestHandler.handle(self) + 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 + if self.server.shutdown_signal: + self.initiate_shutdown() + + def initiate_shutdown(self) -> None: + if is_running_from_reloader(): + # Windows does not provide SIGKILL, go with SIGTERM then. + sig = getattr(signal, "SIGKILL", signal.SIGTERM) + os.kill(os.getpid(), sig) + + self.server._BaseServer__shutdown_request = True # type: ignore + + 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 handle_one_request(self) -> None: + """Handle a single HTTP request.""" + self.raw_requestline = self.rfile.readline() + if not self.raw_requestline: + self.close_connection = True + elif self.parse_request(): + self.run_wsgi() + + def send_response(self, code: int, message: t.Optional[str] = None) -> None: + """Send the response header and log the response code.""" + self.log_request(code) + if message is None: + message = self.responses[code][0] if code in self.responses else "" + if self.request_version != "HTTP/0.9": + hdr = f"{self.protocol_version} {code} {message}\r\n" + self.wfile.write(hdr.encode("ascii")) + + def version_string(self) -> str: + return super().version_string().strip() + + 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 _log_add_style: + 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: + 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): + + """Simple single-threaded, single-process WSGI server.""" + + 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 + + self.address_family = select_address_family(host, port) + + if fd is not None: + real_sock = socket.fromfd(fd, self.address_family, socket.SOCK_STREAM) + port = 0 + + server_address = get_sockaddr(host, int(port), self.address_family) + + # remove socket file if it already exists + if self.address_family == af_unix: + server_address = t.cast(str, server_address) + + if os.path.exists(server_address): + os.unlink(server_address) + + super().__init__(server_address, handler) # type: ignore + + self.app = app + self.passthrough_errors = passthrough_errors + self.shutdown_signal = False + self.host = host + self.port = self.socket.getsockname()[1] + + # Patch in the original socket. + if fd is not None: + self.socket.close() + self.socket = real_sock + self.server_address = self.socket.getsockname() + + if ssl_context is not None: + if isinstance(ssl_context, tuple): + ssl_context = load_ssl_context(*ssl_context) + if 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: + self.shutdown_signal = False + 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) + + +class ThreadedWSGIServer(socketserver.ThreadingMixIn, BaseWSGIServer): + + """A WSGI server that does threading.""" + + multithread = True + daemon_threads = True + + +class ForkingWSGIServer(ForkingMixIn, BaseWSGIServer): + + """A WSGI server that does forking.""" + + 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.") + BaseWSGIServer.__init__( + self, 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 a new server instance that is either threaded, or forks + or just processes one request after another. + """ + if threaded and processes > 1: + raise ValueError("cannot have a multithreaded and multi process server.") + elif threaded: + return ThreadedWSGIServer( + host, port, app, request_handler, passthrough_errors, ssl_context, fd=fd + ) + elif processes > 1: + return ForkingWSGIServer( + host, + port, + app, + processes, + request_handler, + passthrough_errors, + ssl_context, + fd=fd, + ) + else: + return BaseWSGIServer( + host, port, app, request_handler, passthrough_errors, ssl_context, fd=fd + ) + + +def is_running_from_reloader() -> bool: + """Checks if the application is running from within the Werkzeug + reloader subprocess. + + .. versionadded:: 0.10 + """ + return os.environ.get("WERKZEUG_RUN_MAIN") == "true" + + +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 WSGI application. Optional features include a reloader, + multithreading and fork support. + + This function has a command-line interface too:: + + python -m werkzeug.serving --help + + .. versionchanged:: 2.0 + Added ``exclude_patterns`` parameter. + + .. versionadded:: 0.5 + `static_files` was added to simplify serving of static files as well + as `passthrough_errors`. + + .. versionadded:: 0.6 + support for SSL was added. + + .. versionadded:: 0.8 + Added support for automatically loading a SSL context from certificate + file and private key. + + .. versionadded:: 0.9 + Added command-line interface. + + .. versionadded:: 0.10 + Improved the reloader and added support for changing the backend + through the `reloader_type` parameter. See :ref:`reloader` + for more information. + + .. versionchanged:: 0.15 + Bind to a Unix socket by passing a path that starts with + ``unix://`` as the ``hostname``. + + :param hostname: The host to bind to, for example ``'localhost'``. + If the value is a path that starts with ``unix://`` it will bind + to a Unix socket instead of a TCP socket.. + :param port: The port for the server. eg: ``8080`` + :param application: the WSGI application to execute + :param use_reloader: should the server automatically restart the python + process if modules were changed? + :param use_debugger: should the werkzeug debugging system be used? + :param use_evalex: should the exception evaluation feature be enabled? + :param extra_files: a list of files the reloader should watch + additionally to the modules. For example configuration + files. + :param exclude_patterns: List of :mod:`fnmatch` patterns to ignore + when running the reloader. For example, ignore cache files that + shouldn't reload when updated. + :param reloader_interval: the interval for the reloader in seconds. + :param reloader_type: the type of reloader to use. The default is + auto detection. Valid values are ``'stat'`` and + ``'watchdog'``. See :ref:`reloader` for more + information. + :param threaded: should the process handle each request in a separate + thread? + :param processes: if greater than 1 then handle each request in a new process + up to this maximum number of concurrent processes. + :param request_handler: optional parameter that can be used to replace + the default one. You can use this to replace it + with a different + :class:`~BaseHTTPServer.BaseHTTPRequestHandler` + subclass. + :param static_files: a list or dict of paths for static files. This works + exactly like :class:`SharedDataMiddleware`, it's actually + just wrapping the application in that middleware before + serving. + :param passthrough_errors: set this to `True` to disable the error catching. + This means that the server will die on errors but + it can be useful to hook debuggers in (pdb etc.) + :param ssl_context: an SSL context for the connection. Either an + :class:`ssl.SSLContext`, a tuple in the form + ``(cert_file, pkey_file)``, the string ``'adhoc'`` if + the server should automatically create one, or ``None`` + to disable SSL (which is the default). + """ + if not isinstance(port, int): + raise TypeError("port must be an integer") + if use_debugger: + from .debug import DebuggedApplication + + application = DebuggedApplication(application, use_evalex) + if static_files: + from .middleware.shared_data import SharedDataMiddleware + + application = SharedDataMiddleware(application, static_files) + + def log_startup(sock: socket.socket) -> None: + all_addresses_message = ( + " * Running on all addresses.\n" + " WARNING: This is a development server. Do not use it in" + " a production deployment." + ) + + if sock.family == af_unix: + _log("info", " * Running on %s (Press CTRL+C to quit)", hostname) + else: + if hostname == "0.0.0.0": + _log("warning", all_addresses_message) + display_hostname = get_interface_ip(socket.AF_INET) + elif hostname == "::": + _log("warning", all_addresses_message) + display_hostname = get_interface_ip(socket.AF_INET6) + else: + display_hostname = hostname + + if ":" in display_hostname: + display_hostname = f"[{display_hostname}]" + + _log( + "info", + " * Running on %s://%s:%d/ (Press CTRL+C to quit)", + "http" if ssl_context is None else "https", + display_hostname, + sock.getsockname()[1], + ) + + def inner() -> None: + try: + fd: t.Optional[int] = int(os.environ["WERKZEUG_SERVER_FD"]) + except (LookupError, ValueError): + fd = None + srv = make_server( + hostname, + port, + application, + threaded, + processes, + request_handler, + passthrough_errors, + ssl_context, + fd=fd, + ) + if fd is None: + log_startup(srv.socket) + srv.serve_forever() + + if use_reloader: + # If we're not running already in the subprocess that is the + # reloader we want to open up a socket early to make sure the + # port is actually available. + if not is_running_from_reloader(): + if port == 0 and not can_open_by_fd: + raise ValueError( + "Cannot bind to a random port with enabled " + "reloader if the Python interpreter does " + "not support socket opening by fd." + ) + + # Create and destroy a socket so that any exceptions are + # raised before we spawn a separate Python interpreter and + # lose this ability. + 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.bind(server_address) + s.set_inheritable(True) + + # If we can open the socket by file descriptor, then we can just + # reuse this one and our socket will survive the restarts. + if can_open_by_fd: + os.environ["WERKZEUG_SERVER_FD"] = str(s.fileno()) + s.listen(LISTEN_QUEUE) + log_startup(s) + else: + s.close() + if address_family == af_unix: + server_address = t.cast(str, server_address) + _log("info", "Unlinking %s", server_address) + os.unlink(server_address) + + from ._reloader import run_with_reloader as _rwr + + _rwr( + inner, + extra_files=extra_files, + exclude_patterns=exclude_patterns, + interval=reloader_interval, + reloader_type=reloader_type, + ) + else: + inner() + + +def run_with_reloader(*args: t.Any, **kwargs: t.Any) -> None: + """Run a process with the reloader. This is not a public API, do + not use this function. + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. + """ + from ._reloader import run_with_reloader as _rwr + + warnings.warn( + ( + "'run_with_reloader' is a private API, it will no longer be" + " accessible in Werkzeug 2.1. Use 'run_simple' instead." + ), + DeprecationWarning, + stacklevel=2, + ) + _rwr(*args, **kwargs) + + +def main() -> None: + """A simple command-line interface for :py:func:`run_simple`.""" + import argparse + from .utils import import_string + + _log("warning", "This CLI is deprecated and will be removed in version 2.1.") + + parser = argparse.ArgumentParser( + description="Run the given WSGI application with the development server.", + allow_abbrev=False, + ) + parser.add_argument( + "-b", + "--bind", + dest="address", + help="The hostname:port the app should listen on.", + ) + parser.add_argument( + "-d", + "--debug", + action="store_true", + help="Show the interactive debugger for unhandled exceptions.", + ) + parser.add_argument( + "-r", + "--reload", + action="store_true", + help="Reload the process if modules change.", + ) + parser.add_argument( + "application", help="Application to import and serve, in the form module:app." + ) + args = parser.parse_args() + hostname, port = None, None + + if args.address: + hostname, _, port = args.address.partition(":") + + run_simple( + hostname=hostname or "127.0.0.1", + port=int(port or 5000), + application=import_string(args.application), + use_reloader=args.reload, + use_debugger=args.debug, + ) + + +if __name__ == "__main__": + main() diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/test.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/test.py new file mode 100644 index 0000000..448dbbd --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/test.py @@ -0,0 +1,1331 @@ +import mimetypes +import sys +import typing as t +import warnings +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 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 + + 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.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 perecent-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 and pieces[1].isdigit(): + return int(pieces[1]) + 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() + + if content_type is not None: + result["CONTENT_TYPE"] = content_type + headers.set("Content-Type", content_type) + + if content_length is not None: + result["CONTENT_LENGTH"] = str(content_length) + headers.set("Content-Length", 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.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, + as_tuple: bool = False, + 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.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"] = [] + + while follow_redirects and 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, or not + # following 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) + + if as_tuple: + warnings.warn( + "'as_tuple' is deprecated and will be removed in" + " Werkzeug 2.1. Access 'response.request.environ'" + " instead.", + DeprecationWarning, + stacklevel=2, + ) + return request.environ, response # type: ignore + + 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``. + """ + + 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 + + def __iter__(self) -> t.Iterator: + warnings.warn( + ( + "The test client no longer returns a tuple, it returns" + " a 'TestResponse'. Tuple unpacking is deprecated and" + " will be removed in Werkzeug 2.1. Access the" + " attributes 'data', 'status', and 'headers' instead." + ), + DeprecationWarning, + stacklevel=2, + ) + return iter(self._compat_tuple) + + def __getitem__(self, item: int) -> t.Any: + warnings.warn( + ( + "The test client no longer returns a tuple, it returns" + " a 'TestResponse'. Item indexing is deprecated and" + " will be removed in Werkzeug 2.1. Access the" + " attributes 'data', 'status', and 'headers' instead." + ), + DeprecationWarning, + stacklevel=2, + ) + return self._compat_tuple[item] diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/testapp.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/testapp.py new file mode 100644 index 0000000..981f887 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/testapp.py @@ -0,0 +1,240 @@ +"""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 html import escape +from textwrap import wrap + +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(escape(repr(value)))) + wsgi_env.append(f"{escape(str(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/src/myvenv/lib/python3.10/site-packages/werkzeug/urls.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/urls.py new file mode 100644 index 0000000..9529da0 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/urls.py @@ -0,0 +1,1211 @@ +"""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 +import warnings + +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"-._~" + ) +) + +_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", + decode_keys: None = None, + 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 decode_keys is not None: + warnings.warn( + "'decode_keys' is deprecated and will be removed in Werkzeug 2.1.", + DeprecationWarning, + stacklevel=2, + ) + 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", + decode_keys: None = None, + include_empty: bool = True, + errors: str = "replace", + separator: bytes = b"&", + cls: t.Optional[t.Type["ds.MultiDict"]] = None, + limit: t.Optional[int] = None, + return_iterator: bool = False, +) -> "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 + + if decode_keys is not None: + warnings.warn( + "'decode_keys' is deprecated and will be removed in Werkzeug 2.1.", + DeprecationWarning, + stacklevel=2, + ) + + pair_iter = make_chunk_iter(stream, separator, limit) + decoder = _url_decode_impl(pair_iter, charset, include_empty, errors) + + if return_iterator: + warnings.warn( + "'return_iterator' is deprecated and will be removed in Werkzeug 2.1.", + DeprecationWarning, + stacklevel=2, + ) + return decoder # type: ignore + + 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", + encode_keys: None = None, + 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. + """ + if encode_keys is not None: + warnings.warn( + "'encode_keys' is deprecated and will be removed in Werkzeug 2.1.", + DeprecationWarning, + stacklevel=2, + ) + 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", + encode_keys: None = None, + 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 + """ + if encode_keys is not None: + warnings.warn( + "'encode_keys' is deprecated and will be removed in Werkzeug 2.1.", + DeprecationWarning, + stacklevel=2, + ) + 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)) + + +class Href: + """Implements a callable that constructs URLs with the given base. The + function can be called with any number of positional and keyword + arguments which than are used to assemble the URL. Works with URLs + and posix paths. + + Positional arguments are appended as individual segments to + the path of the URL: + + >>> href = Href('/foo') + >>> href('bar', 23) + '/foo/bar/23' + >>> href('foo', bar=23) + '/foo/foo?bar=23' + + If any of the arguments (positional or keyword) evaluates to `None` it + will be skipped. If no keyword arguments are given the last argument + can be a :class:`dict` or :class:`MultiDict` (or any other dict subclass), + otherwise the keyword arguments are used for the query parameters, cutting + off the first trailing underscore of the parameter name: + + >>> href(is_=42) + '/foo?is=42' + >>> href({'foo': 'bar'}) + '/foo?foo=bar' + + Combining of both methods is not allowed: + + >>> href({'foo': 'bar'}, bar=42) + Traceback (most recent call last): + ... + TypeError: keyword arguments and query-dicts can't be combined + + Accessing attributes on the href object creates a new href object with + the attribute name as prefix: + + >>> bar_href = href.bar + >>> bar_href("blub") + '/foo/bar/blub' + + If `sort` is set to `True` the items are sorted by `key` or the default + sorting algorithm: + + >>> href = Href("/", sort=True) + >>> href(a=1, b=2, c=3) + '/?a=1&b=2&c=3' + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. Use :mod:`werkzeug.routing` + instead. + + .. versionadded:: 0.5 + `sort` and `key` were added. + """ + + def __init__( # type: ignore + self, base="./", charset="utf-8", sort=False, key=None + ): + warnings.warn( + "'Href' is deprecated and will be removed in Werkzeug 2.1." + " Use 'werkzeug.routing' instead.", + DeprecationWarning, + stacklevel=2, + ) + + if not base: + base = "./" + self.base = base + self.charset = charset + self.sort = sort + self.key = key + + def __getattr__(self, name): # type: ignore + if name[:2] == "__": + raise AttributeError(name) + base = self.base + if base[-1:] != "/": + base += "/" + return Href(url_join(base, name), self.charset, self.sort, self.key) + + def __call__(self, *path, **query): # type: ignore + if path and isinstance(path[-1], dict): + if query: + raise TypeError("keyword arguments and query-dicts can't be combined") + query, path = path[-1], path[:-1] + elif query: + query = {k[:-1] if k.endswith("_") else k: v for k, v in query.items()} + path = "/".join( + [ + _to_str(url_quote(x, self.charset), "ascii") + for x in path + if x is not None + ] + ).lstrip("/") + rv = self.base + if path: + if not rv.endswith("/"): + rv += "/" + rv = url_join(rv, f"./{path}") + if query: + rv += "?" + _to_str( + url_encode(query, self.charset, sort=self.sort, key=self.key), "ascii" + ) + return rv diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/user_agent.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/user_agent.py new file mode 100644 index 0000000..66ffcbe --- /dev/null +++ b/src/myvenv/lib/python3.10/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/src/myvenv/lib/python3.10/site-packages/werkzeug/useragents.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/useragents.py new file mode 100644 index 0000000..4deed8f --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/useragents.py @@ -0,0 +1,215 @@ +import re +import typing as t +import warnings + +from .user_agent import UserAgent as _BaseUserAgent + +if t.TYPE_CHECKING: + from _typeshed.wsgi import WSGIEnvironment + + +class _UserAgentParser: + platform_rules: t.ClassVar[t.Iterable[t.Tuple[str, str]]] = ( + (" cros ", "chromeos"), + ("iphone|ios", "iphone"), + ("ipad", "ipad"), + (r"darwin\b|mac\b|os\s*x", "macos"), + ("win", "windows"), + (r"android", "android"), + ("netbsd", "netbsd"), + ("openbsd", "openbsd"), + ("freebsd", "freebsd"), + ("dragonfly", "dragonflybsd"), + ("(sun|i86)os", "solaris"), + (r"x11\b|lin(\b|ux)?", "linux"), + (r"nintendo\s+wii", "wii"), + ("irix", "irix"), + ("hp-?ux", "hpux"), + ("aix", "aix"), + ("sco|unix_sv", "sco"), + ("bsd", "bsd"), + ("amiga", "amiga"), + ("blackberry|playbook", "blackberry"), + ("symbian", "symbian"), + ) + browser_rules: t.ClassVar[t.Iterable[t.Tuple[str, str]]] = ( + ("googlebot", "google"), + ("msnbot", "msn"), + ("yahoo", "yahoo"), + ("ask jeeves", "ask"), + (r"aol|america\s+online\s+browser", "aol"), + (r"opera|opr", "opera"), + ("edge|edg", "edge"), + ("chrome|crios", "chrome"), + ("seamonkey", "seamonkey"), + ("firefox|firebird|phoenix|iceweasel", "firefox"), + ("galeon", "galeon"), + ("safari|version", "safari"), + ("webkit", "webkit"), + ("camino", "camino"), + ("konqueror", "konqueror"), + ("k-meleon", "kmeleon"), + ("netscape", "netscape"), + (r"msie|microsoft\s+internet\s+explorer|trident/.+? rv:", "msie"), + ("lynx", "lynx"), + ("links", "links"), + ("Baiduspider", "baidu"), + ("bingbot", "bing"), + ("mozilla", "mozilla"), + ) + + _browser_version_re = r"(?:{pattern})[/\sa-z(]*(\d+[.\da-z]+)?" + _language_re = re.compile( + r"(?:;\s*|\s+)(\b\w{2}\b(?:-\b\w{2}\b)?)\s*;|" + r"(?:\(|\[|;)\s*(\b\w{2}\b(?:-\b\w{2}\b)?)\s*(?:\]|\)|;)" + ) + + def __init__(self) -> None: + self.platforms = [(b, re.compile(a, re.I)) for a, b in self.platform_rules] + self.browsers = [ + (b, re.compile(self._browser_version_re.format(pattern=a), re.I)) + for a, b in self.browser_rules + ] + + def __call__( + self, user_agent: str + ) -> t.Tuple[t.Optional[str], t.Optional[str], t.Optional[str], t.Optional[str]]: + platform: t.Optional[str] + browser: t.Optional[str] + version: t.Optional[str] + language: t.Optional[str] + + for platform, regex in self.platforms: # noqa: B007 + match = regex.search(user_agent) + if match is not None: + break + else: + platform = None + + # Except for Trident, all browser key words come after the last ')' + last_closing_paren = 0 + if ( + not re.compile(r"trident/.+? rv:", re.I).search(user_agent) + and ")" in user_agent + and user_agent[-1] != ")" + ): + last_closing_paren = user_agent.rindex(")") + + for browser, regex in self.browsers: # noqa: B007 + match = regex.search(user_agent[last_closing_paren:]) + if match is not None: + version = match.group(1) + break + else: + browser = version = None + match = self._language_re.search(user_agent) + if match is not None: + language = match.group(1) or match.group(2) + else: + language = None + return platform, browser, version, language + + +# It wasn't public, but users might have imported it anyway, show a +# warning if a user created an instance. +class UserAgentParser(_UserAgentParser): + """A simple user agent parser. Used by the `UserAgent`. + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. Use a dedicated parser library + instead. + """ + + def __init__(self) -> None: + warnings.warn( + "'UserAgentParser' is deprecated and will be removed in" + " Werkzeug 2.1. Use a dedicated parser library instead.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__() + + +class _deprecated_property(property): + def __init__(self, fget: t.Callable[["_UserAgent"], t.Any]) -> None: + super().__init__(fget) + self.message = ( + "The built-in user agent parser is deprecated and will be" + f" removed in Werkzeug 2.1. The {fget.__name__!r} property" + " will be 'None'. Subclass 'werkzeug.user_agent.UserAgent'" + " and set 'Request.user_agent_class' to use a different" + " parser." + ) + + def __get__(self, *args: t.Any, **kwargs: t.Any) -> t.Any: + warnings.warn(self.message, DeprecationWarning, stacklevel=3) + return super().__get__(*args, **kwargs) + + +# This is what Request.user_agent returns for now, only show warnings on +# attribute access, not creation. +class _UserAgent(_BaseUserAgent): + _parser = _UserAgentParser() + + def __init__(self, string: str) -> None: + super().__init__(string) + info = self._parser(string) + self._platform, self._browser, self._version, self._language = info + + @_deprecated_property + def platform(self) -> t.Optional[str]: # type: ignore + return self._platform + + @_deprecated_property + def browser(self) -> t.Optional[str]: # type: ignore + return self._browser + + @_deprecated_property + def version(self) -> t.Optional[str]: # type: ignore + return self._version + + @_deprecated_property + def language(self) -> t.Optional[str]: # type: ignore + return self._language + + +# This is what users might be importing, show warnings on create. +class UserAgent(_UserAgent): + """Represents a parsed user agent header value. + + This uses a basic parser to try to extract some information from the + header. + + :param environ_or_string: The header value to parse, or a WSGI + environ containing the header. + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. Subclass + :class:`werkzeug.user_agent.UserAgent` (note the new module + name) to use a dedicated parser instead. + + .. versionchanged:: 2.0 + Passing a WSGI environ is deprecated and will be removed in 2.1. + """ + + def __init__(self, environ_or_string: "t.Union[str, WSGIEnvironment]") -> None: + if isinstance(environ_or_string, dict): + warnings.warn( + "Passing an environ to 'UserAgent' is deprecated and" + " will be removed in Werkzeug 2.1. Pass the header" + " value string instead.", + DeprecationWarning, + stacklevel=2, + ) + string = environ_or_string.get("HTTP_USER_AGENT", "") + else: + string = environ_or_string + + warnings.warn( + "The 'werkzeug.useragents' module is deprecated and will be" + " removed in Werkzeug 2.1. The new base API is" + " 'werkzeug.user_agent.UserAgent'.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(string) diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/utils.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/utils.py new file mode 100644 index 0000000..9007231 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/utils.py @@ -0,0 +1,1099 @@ +import codecs +import io +import mimetypes +import os +import pkgutil +import re +import sys +import typing as t +import unicodedata +import warnings +from datetime import datetime +from html.entities import name2codepoint +from time import time +from zlib import adler32 + +from ._internal import _DictAccessorProperty +from ._internal import _missing +from ._internal import _parse_signature +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 + + The class must have a ``__dict__`` for this to work. + + .. 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.__module__ = fget.__module__ + + def __set__(self, obj: object, value: _T) -> None: + obj.__dict__[self.__name__] = value + + def __get__(self, obj: object, type: type = None) -> _T: # type: ignore + if obj is None: + return self # type: ignore + + value: _T = obj.__dict__.get(self.__name__, _missing) + + if value is _missing: + value = self.fget(obj) # type: ignore + obj.__dict__[self.__name__] = value + + return value + + def __delete__(self, obj: object) -> None: + del obj.__dict__[self.__name__] + + +def invalidate_cached_property(obj: object, name: str) -> None: + """Invalidates the cache for a :class:`cached_property`: + + >>> class Test(object): + ... @cached_property + ... def magic_number(self): + ... print("recalculating...") + ... return 42 + ... + >>> var = Test() + >>> var.magic_number + recalculating... + 42 + >>> var.magic_number + 42 + >>> invalidate_cached_property(var, "magic_number") + >>> var.magic_number + recalculating... + 42 + + You must pass the name of the cached property as the second argument. + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. Use ``del obj.name`` instead. + """ + warnings.warn( + "'invalidate_cached_property' is deprecated and will be removed" + " in Werkzeug 2.1. Use 'del obj.name' instead.", + DeprecationWarning, + stacklevel=2, + ) + delattr(obj, name) + + +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 + + +class HTMLBuilder: + """Helper object for HTML generation. + + Per default there are two instances of that class. The `html` one, and + the `xhtml` one for those two dialects. The class uses keyword parameters + and positional parameters to generate small snippets of HTML. + + Keyword parameters are converted to XML/SGML attributes, positional + arguments are used as children. Because Python accepts positional + arguments before keyword arguments it's a good idea to use a list with the + star-syntax for some children: + + >>> html.p(class_='foo', *[html.a('foo', href='foo.html'), ' ', + ... html.a('bar', href='bar.html')]) + '

    foo bar

    ' + + This class works around some browser limitations and can not be used for + arbitrary SGML/XML generation. For that purpose lxml and similar + libraries exist. + + Calling the builder escapes the string passed: + + >>> html.p(html("")) + '

    <foo>

    ' + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. + """ + + _entity_re = re.compile(r"&([^;]+);") + _entities = name2codepoint.copy() + _entities["apos"] = 39 + _empty_elements = { + "area", + "base", + "basefont", + "br", + "col", + "command", + "embed", + "frame", + "hr", + "img", + "input", + "keygen", + "isindex", + "link", + "meta", + "param", + "source", + "wbr", + } + _boolean_attributes = { + "selected", + "checked", + "compact", + "declare", + "defer", + "disabled", + "ismap", + "multiple", + "nohref", + "noresize", + "noshade", + "nowrap", + } + _plaintext_elements = {"textarea"} + _c_like_cdata = {"script", "style"} + + def __init__(self, dialect): # type: ignore + self._dialect = dialect + + def __call__(self, s): # type: ignore + import html + + warnings.warn( + "'utils.HTMLBuilder' is deprecated and will be removed in Werkzeug 2.1.", + DeprecationWarning, + stacklevel=2, + ) + return html.escape(s) + + def __getattr__(self, tag): # type: ignore + import html + + warnings.warn( + "'utils.HTMLBuilder' is deprecated and will be removed in Werkzeug 2.1.", + DeprecationWarning, + stacklevel=2, + ) + if tag[:2] == "__": + raise AttributeError(tag) + + def proxy(*children, **arguments): # type: ignore + buffer = f"<{tag}" + for key, value in arguments.items(): + if value is None: + continue + if key[-1] == "_": + key = key[:-1] + if key in self._boolean_attributes: + if not value: + continue + if self._dialect == "xhtml": + value = f'="{key}"' + else: + value = "" + else: + value = f'="{html.escape(value)}"' + buffer += f" {key}{value}" + if not children and tag in self._empty_elements: + if self._dialect == "xhtml": + buffer += " />" + else: + buffer += ">" + return buffer + buffer += ">" + + children_as_string = "".join([str(x) for x in children if x is not None]) + + if children_as_string: + if tag in self._plaintext_elements: + children_as_string = html.escape(children_as_string) + elif tag in self._c_like_cdata and self._dialect == "xhtml": + children_as_string = f"/**/" + buffer += children_as_string + f"" + return buffer + + return proxy + + def __repr__(self) -> str: + return f"<{type(self).__name__} for {self._dialect!r}>" + + +html = HTMLBuilder("html") +xhtml = HTMLBuilder("xhtml") + +# 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 detect_utf_encoding(data: bytes) -> str: + """Detect which UTF encoding was used to encode the given bytes. + + The latest JSON standard (:rfc:`8259`) suggests that only UTF-8 is + accepted. Older documents allowed 8, 16, or 32. 16 and 32 can be big + or little endian. Some editors or libraries may prepend a BOM. + + :internal: + + :param data: Bytes in unknown UTF encoding. + :return: UTF encoding name + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. This is built in to + :func:`json.loads`. + + .. versionadded:: 0.15 + """ + warnings.warn( + "'detect_utf_encoding' is deprecated and will be removed in" + " Werkzeug 2.1. This is built in to 'json.loads'.", + DeprecationWarning, + stacklevel=2, + ) + head = data[:4] + + if head[:3] == codecs.BOM_UTF8: + return "utf-8-sig" + + if b"\x00" not in head: + return "utf-8" + + if head in (codecs.BOM_UTF32_BE, codecs.BOM_UTF32_LE): + return "utf-32" + + if head[:2] in (codecs.BOM_UTF16_BE, codecs.BOM_UTF16_LE): + return "utf-16" + + if len(head) == 4: + if head[:3] == b"\x00\x00\x00": + return "utf-32-be" + + if head[::2] == b"\x00\x00": + return "utf-16-be" + + if head[1:] == b"\x00\x00\x00": + return "utf-32-le" + + if head[1::2] == b"\x00\x00": + return "utf-16-le" + + if len(head) == 2: + return "utf-16-be" if head.startswith(b"\x00") else "utf-16-le" + + return "utf-8" + + +def format_string(string: str, context: t.Mapping[str, t.Any]) -> str: + """String-template format a string: + + >>> format_string('$foo and ${foo}s', dict(foo=42)) + '42 and 42s' + + This does not do any attribute lookup. + + :param string: the format string. + :param context: a dict with the variables to insert. + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. Use :class:`string.Template` + instead. + """ + from string import Template + + warnings.warn( + "'utils.format_string' is deprecated and will be removed in" + " Werkzeug 2.1. Use 'string.Template' instead.", + DeprecationWarning, + stacklevel=2, + ) + return Template(string).substitute(context) + + +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 escape(s: t.Any) -> str: + """Replace ``&``, ``<``, ``>``, ``"``, and ``'`` with HTML-safe + sequences. + + ``None`` is escaped to an empty string. + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. Use MarkupSafe instead. + """ + import html + + warnings.warn( + "'utils.escape' is deprecated and will be removed in Werkzeug" + " 2.1. Use MarkupSafe instead.", + DeprecationWarning, + stacklevel=2, + ) + + if s is None: + return "" + + if hasattr(s, "__html__"): + return s.__html__() # type: ignore + + if not isinstance(s, str): + s = str(s) + + return html.escape(s, quote=True) # type: ignore + + +def unescape(s: str) -> str: + """The reverse of :func:`escape`. This unescapes all the HTML + entities, not only those inserted by ``escape``. + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. Use MarkupSafe instead. + """ + import html + + warnings.warn( + "'utils.unescape' is deprecated and will be removed in Werkzueg" + " 2.1. Use MarkupSafe instead.", + DeprecationWarning, + stacklevel=2, + ) + return html.unescape(s) + + +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. + """ + import html + + if Response is None: + from .wrappers import Response # type: ignore + + display_location = html.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' + "Redirecting...\n" + "

    Redirecting...

    \n" + "

    You should be redirected automatically to target URL: " + f'{display_location}. If' + " not click the link.", + code, + mimetype="text/html", + ) + response.headers["Location"] = location + return response + + +def append_slash_redirect(environ: "WSGIEnvironment", code: int = 301) -> "Response": + """Redirects to the same URL but with a slash appended. The behavior + of this function is undefined if the path ends with a slash already. + + :param environ: the WSGI environment for the request that triggers + the redirect. + :param code: the status code for the redirect. + """ + new_path = environ["PATH_INFO"].strip("/") + "/" + query_string = environ.get("QUERY_STRING") + if query_string: + new_path += f"?{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 + + +def validate_arguments(func, args, kwargs, drop_extra=True): # type: ignore + """Checks if the function accepts the arguments and keyword arguments. + Returns a new ``(args, kwargs)`` tuple that can safely be passed to + the function without causing a `TypeError` because the function signature + is incompatible. If `drop_extra` is set to `True` (which is the default) + any extra positional or keyword arguments are dropped automatically. + + The exception raised provides three attributes: + + `missing` + A set of argument names that the function expected but where + missing. + + `extra` + A dict of keyword arguments that the function can not handle but + where provided. + + `extra_positional` + A list of values that where given by positional argument but the + function cannot accept. + + This can be useful for decorators that forward user submitted data to + a view function:: + + from werkzeug.utils import ArgumentValidationError, validate_arguments + + def sanitize(f): + def proxy(request): + data = request.values.to_dict() + try: + args, kwargs = validate_arguments(f, (request,), data) + except ArgumentValidationError: + raise BadRequest('The browser failed to transmit all ' + 'the data expected.') + return f(*args, **kwargs) + return proxy + + :param func: the function the validation is performed against. + :param args: a tuple of positional arguments. + :param kwargs: a dict of keyword arguments. + :param drop_extra: set to `False` if you don't want extra arguments + to be silently dropped. + :return: tuple in the form ``(args, kwargs)``. + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. Use :func:`inspect.signature` + instead. + """ + warnings.warn( + "'utils.validate_arguments' is deprecated and will be removed" + " in Werkzeug 2.1. Use 'inspect.signature' instead.", + DeprecationWarning, + stacklevel=2, + ) + parser = _parse_signature(func) + args, kwargs, missing, extra, extra_positional = parser(args, kwargs)[:5] + if missing: + raise ArgumentValidationError(tuple(missing)) + elif (extra or extra_positional) and not drop_extra: + raise ArgumentValidationError(None, extra, extra_positional) + return tuple(args), kwargs + + +def bind_arguments(func, args, kwargs): # type: ignore + """Bind the arguments provided into a dict. When passed a function, + a tuple of arguments and a dict of keyword arguments `bind_arguments` + returns a dict of names as the function would see it. This can be useful + to implement a cache decorator that uses the function arguments to build + the cache key based on the values of the arguments. + + :param func: the function the arguments should be bound for. + :param args: tuple of positional arguments. + :param kwargs: a dict of keyword arguments. + :return: a :class:`dict` of bound keyword arguments. + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. Use :meth:`Signature.bind` + instead. + """ + warnings.warn( + "'utils.bind_arguments' is deprecated and will be removed in" + " Werkzeug 2.1. Use 'Signature.bind' instead.", + DeprecationWarning, + stacklevel=2, + ) + ( + args, + kwargs, + missing, + extra, + extra_positional, + arg_spec, + vararg_var, + kwarg_var, + ) = _parse_signature(func)(args, kwargs) + values = {} + for (name, _has_default, _default), value in zip(arg_spec, args): + values[name] = value + if vararg_var is not None: + values[vararg_var] = tuple(extra_positional) + elif extra_positional: + raise TypeError("too many positional arguments") + if kwarg_var is not None: + multikw = set(extra) & {x[0] for x in arg_spec} + if multikw: + raise TypeError( + f"got multiple values for keyword argument {next(iter(multikw))!r}" + ) + values[kwarg_var] = extra + elif extra: + raise TypeError(f"got unexpected keyword argument {next(iter(extra))!r}") + return values + + +class ArgumentValidationError(ValueError): + """Raised if :func:`validate_arguments` fails to validate + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1 along with ``utils.bind`` and + ``validate_arguments``. + """ + + def __init__(self, missing=None, extra=None, extra_positional=None): # type: ignore + self.missing = set(missing or ()) + self.extra = extra or {} + self.extra_positional = extra_positional or [] + super().__init__( + "function arguments invalid." + f" ({len(self.missing)} missing," + f" {len(self.extra) + len(self.extra_positional)} additional)" + ) + + +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/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__init__.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__init__.py new file mode 100644 index 0000000..eb69a99 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__init__.py @@ -0,0 +1,16 @@ +from .accept import AcceptMixin +from .auth import AuthorizationMixin +from .auth import WWWAuthenticateMixin +from .base_request import BaseRequest +from .base_response import BaseResponse +from .common_descriptors import CommonRequestDescriptorsMixin +from .common_descriptors import CommonResponseDescriptorsMixin +from .etag import ETagRequestMixin +from .etag import ETagResponseMixin +from .request import PlainRequest +from .request import Request as Request +from .request import StreamOnlyMixin +from .response import Response as Response +from .response import ResponseStream +from .response import ResponseStreamMixin +from .user_agent import UserAgentMixin diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/__init__.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d114b94dcea02ca436cf2e4636ff7b79666979ae GIT binary patch literal 918 zcmZ{i&2rN)5XbGrNu2m2PMVf*fZ>`0H65-DL-;sSIt@%_bnz&TCJ~ivSCZSN55arz z794m2j=pl@6*#eyV+u1Mk9U6i*Y0YyqdW)(7OXGdPF9~khBBD3%@n&D3$r{yKozsZ^8N;+W3eN7`wKZHQ zK`?)pv0W4Go|E5Qh7H$YkbCgA(jk zh>ZE}iey(YqpP?udryx~p2U(W^0>h11yq;uH4zuLq};^U0v81lGENejQI#ae#jbLn W@qAq}@?5_=`3Q_}`S$<6$o>WE`2yAe literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/accept.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/accept.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a12cacb6aefe83c33f4d0166fcf264eca896bf9a GIT binary patch literal 828 zcmYjPJ#X7E5G5s9QPZR!LEBmA5W_>Ird^Ao0Sa`gQPe{KFN7?f9Xd26law6?*%BaA z`wzNx$-n4t=*YEG{zAL-C>wzZ@bSnyJid2iwZFehaQymxH2Oga`Qta+BgD-IoaQA0 zC!9($r0p6EgHMD9JiI16yb6XPrvuW9?y!#ZOOM+l-fT>U0kj;$fKv#k5f54nc{Gl1 z$e8jDkFWQJof{I7VT_zR?%{D+LTx{bbD>;R=!tRh*>b&Vu#Hyz64l=iueyWtF-~)c zV9AtnY6GwLTS$owugEmIq=H-qKk0W$(VJJ_zcAgcySk|`DTi7^SycKbG we+1)Ok&r{$p7bIY+f|Ld)z5uZ;=z}0akOln!zJ(5V&3~7X1u3_B=jKs4|F8jbN~PV literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/auth.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/auth.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..568cfb1817b145cfc01559c714c66246379c6b3b GIT binary patch literal 1222 zcmbVLJ#Q015Z%2mJHg?@KtKY-Rk2dwOQ4}Zh)76OScnvs+?>w0>tyZo-eq^sj;&B7 zQY!crH2D|&2Fh!xQoDnOnX?I&l1PY^_TA3TdS>3tbGo*+N??8azTJIk6Y>L%Cp0Pb*y)USa^6ArwL z*s&PpcHd!Ei8gb3-YMx(<}&Z3)^SgXLpmPBtQ7T~-0Y`HOd}&w`Cc3fSvZl}(}gz} z&%cVBT*+2Um$D)i7xpdKvkd@4`jk;)A&Jj6CB{A`edmY@a%6p_Unm8_kkDyOr;W=g z8@|v!;k23 zdKi3|K)YqIdytD(YPb%DlM$DrAQ9alD}67T+gpJahCj=o$Y>AVj2FCvv5GRNLkAH| zt(i^KZODuQnAHFrYEjF!sP}8VGJSNp%gu}GE67AfLmr03Y8VbvmM3_wh2cRSB?}KV zg}o!^Ns6@vxtJ$O7^?e_Zw`0yw2tsc6fA(MpBh)i`Cnz}ER~x7yR=jl%1|o^HxTY1l&vW{RrUvmRmb}W0MjQ| zm3uKF^$;Ik)ny+XW%Q@`0`3i|`ri z2ZA1wPU{jhk=`W**`YT0K^|99n-ovi2UxR2{u~yvMg>GF-7yo6^oC5hf?cq_4~XtK zXwDFm^+ORNlHK9oCKGvB4bnW(`q4z$7Fze%)gT-c8?9SJ#8GEIyWQBsI#p5=Kokdczp@&wMZB6=d# zh8`^3xfZl^nsFdE;I@SIKN9m5v7x zBCeKc?#>qW2InhxQ%nixAsF#$3k0JMbsUHKf3^M7yPMhTZhUG(3{g^~@~wGP0cieT zv$cY}Uk=7^%9cWhR10A}bq&|(oZ1F~`B;74%@Nh<9aG zy{c_MdSYBPc8HMd(!G|#vke~OJr3OkvB6_xGw^umKP5vdJmFt#^}VNrk-iTM3+%Nu zep!|%D0P1VwSJ@(D(|RmKB;TrBUrr;Q)2;yd)U)bvFEBS-@Xn+BN=lg(Rd~&UJTh_ivD1yD$I% literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/base_response.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/base_response.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..42883d5aae4a9e97b61b030e27ccf54023e792d0 GIT binary patch literal 1751 zcmb_d&5zqe6rZujjuWz?UAFD=ZK0}ZB#67TM}&Y@aElNNs+7yf@l1A|ICeTS-jLPa zcBP)$KLT;-f5G3taju;9+#7J2#jBTJsAJQ2>A^+ zo5P3A7cliB5P}GrkrAzaoslCP;b!ifjTj~05W$3ZL4+s0b9dy!-WM&{wF_`=}nk$1-oD)A0XXn zt3E?eHVQ<5PxaiOnb|0zSZAY6pnPu`sW_`~F%UI=U zexxnKmEC<*!>2|5cztC%SK5^eO8Sm<0Y#yoFNnGZKflkT<6%GYkw=G5%5+#5siXPoMCK<^mX4!Eb$5Soa4*uSk)JHUtoR7tENlOwrHU5|sdO}k zAaPY^dazj8>zp?ZCzut^1F+&{7X+gYbsUHKe|G%S+uI2oY<+42j8U8?^0lc{Eztb` zCal4{Ta2f#OqfEKR2zXk^#-odJ+%V@Q__52r$oJpmwPBMA!~6R-$JaKw{@)WSiJ?} zHSzh!^C2)H;5?7#l5^YPd|rq$!*!SQCuN+~H`G}6{c0gC8y7{Ub`jkDGGD2ih<9aG zwW@4Dj$&jr_KAS((fzithLW)t-x zIHp1n&=T65R}GHytFloa!QFc>_1~m&fmDCoY@OcN3@6a3*4$FJ;JMmI@iq!(g~sZkGPTeueupwl`^_-dfZX z{0c7p7yJf}d*#$~Zg63|NkfF%g0SRoJ)Yf}`DQ+Cy0Ws2V150z)o!~8eYeKqf;;pI zw%!Dwh+=_SxO_S-=PjZRbx#m=kDZnamPdWCe6T!>y{_Y%`rGo|#nXcl?mc z!i&|OE`r{0`c%y1N;VU`P=ICS!@dQ3vJPNS7gKB;%jc7ek#Ubv*E_--9XVg{XN-Y6 zSrMA&AbV*PXgcU*?MO!dYr-wU5Lwi;o5Mx`Fg zbO`Q5h`P<2(UYK6~4|hriv;dTyjImnOk_8iH`ChqOwhauuFs_BGww*=!c5-(>{y3xi(y~ zXa^{@)5GZf$n2*w+BwL1Gc`;{{n3EQK_qxP%1Yn!#@1$}xnWN;C^FuIcZM_G(NM)1 z)S;uKoFxIi7gKCxBXt|LduC_3 zYVYp@jQ>*je1PhK{p7M4gy1OiJh5+BYr`)BGs-~u>Y=@}qA3ScdKZGsiz=!wriyrJ Qe+$~OsG=&q>8{p(0VQr*#{d8T literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/cors.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/cors.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b8eb7ea0da654c319cfab178259dfa4696b40400 GIT binary patch literal 1207 zcmbVLO>Yx15ViL!+mb?CMEMXBdm`$A-4?D0fk5I!K+U02F00MjX`MRWt?f;ksJB+? z34R5a{tJEs$GvjuIXAd4-VG%xR6+t*k5~SYN(w_d*+?Z^l?$aED&P zR$BlB5zJ8+S6{1Zy+y<#_9-IviPg2ia)=9-3zkE02W@&6@GI0#4K6NkZp=bB(2B8Z z5lroYL#zsI;`F^U)W^gn-f6Szo*@TyJ>YDVtFPbhbav=rL6v^Tj+iK&MDD55I~dnr zNp&GbJH-nzjSv_1E!eZi02&Q2!P+tsKH3;*`veV~W6aR8^%;M{8011Yr#(GtT@Ba@ zmHxG$ah&o*DR86jB-+o0G#V62GeM&cNa|%r(T9oN z&qUNYELc0!R7Jzdh>B6fSue^f-?MOgD^g6;CpjdU?7^GyTz52swh>Bs>+xqt(*J10MiG52)^u$yk}nh zt+)X=D(Xk(g|Rl>($kY1=2kv5cV+;pidWtRlFK|w|9Rc&7v_JgOyWNB@lAWZ`4cO3 BGQ0o) literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/etag.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/etag.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c54fe41f284cfd9e86737fa9ee33d46fb44f58df GIT binary patch literal 1207 zcmbVLO>Yx15ViL!+mb?CMEMXBdur4JyDeN10tv*42vMX;xvVy8Cw1z0x3)KFqTX7m zC-@ay`Y-qm9QVqp=iK1Jc(atKPzhnlZ#^F8&AgdOwz9H}V14%ONgUE?5r1yJ*Y1fM20@YH)FRwJ{6fKr6B6fSvSfn-_vksJ5o&3$2laK^x@68)*X#yl0zOUqB`k^`9!Wl zWYhdv6Trb1wrmS~KQ}%6S~iI}mLSx6Nt8z^{RrnUeTu6IVCaj;b`hfZFG%hb1NU3J2L=P#VhXu$z>j;|7_ms=jMN`OyWNB@lAWZ`4b!N BGok!_#}Sstym^2;$f8k1%r46`I7CSfWev6aT;%oCWRu)vUX_sY|7$T+~LCg%g|>n$v|;ijD*| zVp`4No7D6~nDdorPU*|+IHTRKV%7-jx>Q#SD3_|?!cuo8=(y3Pla(%%bW6%5@H(~3 z?g$9%Vc)i{D9@Fc3)O4+6zplK!D$>a-+8|k0t6?Ul5g3j7RINHNi7{?y~xK_sIdwD zO$>00{XS!*Dy(Jf7X9Va literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/request.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/request.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d64524c8493965b59cd096b206f304f86c9f8aca GIT binary patch literal 21400 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 j!4GjM=a`bte^odd_3r@F^uMW#`w#p-Pej{) literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/response.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/response.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a9c9c0b2bab49fe461c11a84ef71eaf260d5b0bf GIT binary patch literal 29815 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 Lmj0Wm&Yk|>{Z%J4 literal 0 HcmV?d00001 diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/user_agent.cpython-310.pyc b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/__pycache__/user_agent.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..184a72d2ab929593332eaca8116858096b44a7e0 GIT binary patch literal 841 zcmY*X&2AGh5Vm(W+ofvxsRUdt4vlhPm%lxlj%?`mFpFuljuk*c}b-%z#3)Xd+uICu8R4c$TcLZ$I>dMJlmrA+?6B6q> zwa9NGWZ9#B)4H-cRxktA>-Y>cYN=6f5!gO_03{9U)8g~O9o4!xIB8|Sc3_L?Vg`Cv zC^;;eW$aD9_o}ec!OI3omSfDBuXPu5Q#Q!M7A?LO$C!3`voKrOKRmw;PC_FZ#Su;a zJ=-{Yet*vSE&q+6MVC|H+;4I|twpPXzs31UTdH-0Iv?-rRRh1hmREsNoSVnkYXuL3 z_as1=Z}<{6Oe7<_ba~TDeCierj@Ud6Sy_OPdZ)&+TBzZ(w<|L5!e6sNRz@ None: + warnings.warn( + "'AcceptMixin' is deprecated and will be removed in" + " Werkzeug 2.1. 'Request' now includes the functionality" + " directly.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(*args, **kwargs) diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/auth.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/auth.py new file mode 100644 index 0000000..f7f5815 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/auth.py @@ -0,0 +1,26 @@ +import typing as t +import warnings + + +class AuthorizationMixin: + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + warnings.warn( + "'AuthorizationMixin' is deprecated and will be removed in" + " Werkzeug 2.1. 'Request' now includes the functionality" + " directly.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(*args, **kwargs) + + +class WWWAuthenticateMixin: + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + warnings.warn( + "'WWWAuthenticateMixin' is deprecated and will be removed" + " in Werkzeug 2.1. 'Response' now includes the" + " functionality directly.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(*args, **kwargs) diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/base_request.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/base_request.py new file mode 100644 index 0000000..451989f --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/base_request.py @@ -0,0 +1,36 @@ +import typing as t +import warnings + +from .request import Request + + +class _FakeSubclassCheck(type): + def __subclasscheck__(cls, subclass: t.Type) -> bool: + warnings.warn( + "'BaseRequest' is deprecated and will be removed in" + " Werkzeug 2.1. Use 'issubclass(cls, Request)' instead.", + DeprecationWarning, + stacklevel=2, + ) + return issubclass(subclass, Request) + + def __instancecheck__(cls, instance: t.Any) -> bool: + warnings.warn( + "'BaseRequest' is deprecated and will be removed in" + " Werkzeug 2.1. Use 'isinstance(obj, Request)' instead.", + DeprecationWarning, + stacklevel=2, + ) + return isinstance(instance, Request) + + +class BaseRequest(Request, metaclass=_FakeSubclassCheck): + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + warnings.warn( + "'BaseRequest' is deprecated and will be removed in" + " Werkzeug 2.1. 'Request' now includes the functionality" + " directly.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(*args, **kwargs) diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/base_response.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/base_response.py new file mode 100644 index 0000000..3e0dc67 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/base_response.py @@ -0,0 +1,36 @@ +import typing as t +import warnings + +from .response import Response + + +class _FakeSubclassCheck(type): + def __subclasscheck__(cls, subclass: t.Type) -> bool: + warnings.warn( + "'BaseResponse' is deprecated and will be removed in" + " Werkzeug 2.1. Use 'issubclass(cls, Response)' instead.", + DeprecationWarning, + stacklevel=2, + ) + return issubclass(subclass, Response) + + def __instancecheck__(cls, instance: t.Any) -> bool: + warnings.warn( + "'BaseResponse' is deprecated and will be removed in" + " Werkzeug 2.1. Use 'isinstance(obj, Response)' instead.", + DeprecationWarning, + stacklevel=2, + ) + return isinstance(instance, Response) + + +class BaseResponse(Response, metaclass=_FakeSubclassCheck): + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + warnings.warn( + "'BaseResponse' is deprecated and will be removed in" + " Werkzeug 2.1. 'Response' now includes the functionality" + " directly.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(*args, **kwargs) diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/common_descriptors.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/common_descriptors.py new file mode 100644 index 0000000..6436b4c --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/common_descriptors.py @@ -0,0 +1,26 @@ +import typing as t +import warnings + + +class CommonRequestDescriptorsMixin: + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + warnings.warn( + "'CommonRequestDescriptorsMixin' is deprecated and will be" + " removed in Werkzeug 2.1. 'Request' now includes the" + " functionality directly.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(*args, **kwargs) + + +class CommonResponseDescriptorsMixin: + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + warnings.warn( + "'CommonResponseDescriptorsMixin' is deprecated and will be" + " removed in Werkzeug 2.1. 'Response' now includes the" + " functionality directly.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(*args, **kwargs) diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/cors.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/cors.py new file mode 100644 index 0000000..efd8537 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/cors.py @@ -0,0 +1,26 @@ +import typing as t +import warnings + + +class CORSRequestMixin: + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + warnings.warn( + "'CORSRequestMixin' is deprecated and will be removed in" + " Werkzeug 2.1. 'Request' now includes the functionality" + " directly.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(*args, **kwargs) + + +class CORSResponseMixin: + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + warnings.warn( + "'CORSResponseMixin' is deprecated and will be removed in" + " Werkzeug 2.1. 'Response' now includes the functionality" + " directly.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(*args, **kwargs) diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/etag.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/etag.py new file mode 100644 index 0000000..9131b93 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/etag.py @@ -0,0 +1,26 @@ +import typing as t +import warnings + + +class ETagRequestMixin: + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + warnings.warn( + "'ETagRequestMixin' is deprecated and will be removed in" + " Werkzeug 2.1. 'Request' now includes the functionality" + " directly.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(*args, **kwargs) + + +class ETagResponseMixin: + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + warnings.warn( + "'ETagResponseMixin' is deprecated and will be removed in" + " Werkzeug 2.1. 'Response' now includes the functionality" + " directly.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(*args, **kwargs) diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/json.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/json.py new file mode 100644 index 0000000..a4dd7c2 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/json.py @@ -0,0 +1,13 @@ +import typing as t +import warnings + + +class JSONMixin: + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + warnings.warn( + "'JSONMixin' is deprecated and will be removed in Werkzeug" + " 2.1. 'Request' now includes the functionality directly.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(*args, **kwargs) diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/request.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/request.py new file mode 100644 index 0000000..f68dd5a --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/request.py @@ -0,0 +1,660 @@ +import functools +import json +import typing +import typing as t +import warnings +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.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 shoud be used. Can be replaced to customize + #: the form date parsing. + form_data_parser_class: t.Type[FormDataParser] = FormDataParser + + #: Disable the :attr:`data` property to avoid reading from the input + #: stream. + #: + #: .. deprecated:: 2.0 + #: Will be removed in Werkzeug 2.1. Create the request with + #: ``shallow=True`` instead. + #: + #: .. versionadded:: 0.9 + disable_data_descriptor: t.Optional[bool] = None + + #: 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 + + if self.disable_data_descriptor is not None: + warnings.warn( + "'disable_data_descriptor' is deprecated and will be" + " removed in Werkzeug 2.1. Create the request with" + " 'shallow=True' instead.", + DeprecationWarning, + stacklevel=2, + ) + shallow = shallow or self.disable_data_descriptor + + 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. + """ + 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`), this + returns ``None``. + + If parsing fails, :meth:`on_json_loading_failed` is called and + its return value is used as the return value. + + :param force: Ignore the mimetype and always try to parse JSON. + :param silent: Silence parsing errors and return ``None`` + instead. + :param cache: Store the parsed JSON to return for subsequent + calls. + """ + if cache and self._cached_json[silent] is not Ellipsis: + return self._cached_json[silent] + + if not (force or self.is_json): + 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: ValueError) -> t.Any: + """Called if :meth:`get_json` parsing 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`. + """ + raise BadRequest(f"Failed to decode JSON object: {e}") + + +class StreamOnlyMixin: + """Mixin to create a ``Request`` that disables the ``data``, + ``form``, and ``files`` properties. Only ``stream`` is available. + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. Create the request with + ``shallow=True`` instead. + + .. versionadded:: 0.9 + """ + + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + warnings.warn( + "'StreamOnlyMixin' is deprecated and will be removed in" + " Werkzeug 2.1. Create the request with 'shallow=True'" + " instead.", + DeprecationWarning, + stacklevel=2, + ) + kwargs["shallow"] = True + super().__init__(*args, **kwargs) + + +class PlainRequest(StreamOnlyMixin, Request): + """A request object without ``data``, ``form``, and ``files``. + + .. deprecated:: 2.0 + Will be removed in Werkzeug 2.1. Create the request with + ``shallow=True`` instead. + + .. versionadded:: 0.9 + """ + + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + warnings.warn( + "'PlainRequest' is deprecated and will be removed in" + " Werkzeug 2.1. Create the request with 'shallow=True'" + " instead.", + DeprecationWarning, + stacklevel=2, + ) + + # Don't show the DeprecationWarning for StreamOnlyMixin. + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + super().__init__(*args, **kwargs) diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/response.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/response.py new file mode 100644 index 0000000..8378e74 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/response.py @@ -0,0 +1,891 @@ +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 + + #: Should this response object correct the location header to be RFC + #: conformant? This is true by default. + #: + #: .. versionadded:: 0.8 + autocorrect_location_header = True + + #: 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, no_etag: None = None) -> 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.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))) + + if no_etag is not None: + warnings.warn( + "The 'no_etag' parameter is deprecated and will be" + " removed in Werkzeug 2.1.", + DeprecationWarning, + stacklevel=2, + ) + + 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 overriden 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 the :class:`ResponseStreamMixin` 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 + + +class ResponseStreamMixin: + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + warnings.warn( + "'ResponseStreamMixin' is deprecated and will be removed in" + " Werkzeug 2.1. 'Response' now includes the functionality" + " directly.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(*args, **kwargs) diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/user_agent.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/user_agent.py new file mode 100644 index 0000000..e69ab05 --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/wrappers/user_agent.py @@ -0,0 +1,14 @@ +import typing as t +import warnings + + +class UserAgentMixin: + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + warnings.warn( + "'UserAgentMixin' is deprecated and will be removed in" + " Werkzeug 2.1. 'Request' now includes the functionality" + " directly.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(*args, **kwargs) diff --git a/src/myvenv/lib/python3.10/site-packages/werkzeug/wsgi.py b/src/myvenv/lib/python3.10/site-packages/werkzeug/wsgi.py new file mode 100644 index 0000000..9cfa74d --- /dev/null +++ b/src/myvenv/lib/python3.10/site-packages/werkzeug/wsgi.py @@ -0,0 +1,982 @@ +import io +import re +import typing as t +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. + """ + if environ.get("HTTP_TRANSFER_ENCODING", "") == "chunked": + return None + + content_length = environ.get("CONTENT_LENGTH") + if content_length is not None: + try: + return max(0, int(content_length)) + except (ValueError, TypeError): + pass + return None + + +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. + + .. versionadded:: 0.9 + """ + 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. + + .. versionadded:: 0.9 + """ + 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' + + .. 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`. + """ + 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. + + .. 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. + """ + 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. + + .. versionchanged:: 0.15 + The ``errors`` parameter defaults to leaving invalid bytes + quoted instead of replacing them. + + .. versionadded:: 0.6 + """ + + 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/src/myvenv/lib64 b/src/myvenv/lib64 new file mode 120000 index 0000000..7951405 --- /dev/null +++ b/src/myvenv/lib64 @@ -0,0 +1 @@ +lib \ No newline at end of file diff --git a/src/myvenv/pyvenv.cfg b/src/myvenv/pyvenv.cfg new file mode 100644 index 0000000..0d8baee --- /dev/null +++ b/src/myvenv/pyvenv.cfg @@ -0,0 +1,3 @@ +home = /usr/bin +include-system-site-packages = false +version = 3.10.2 diff --git a/src/requirements.txt b/src/requirements.txt new file mode 100644 index 0000000..9021fa0 --- /dev/null +++ b/src/requirements.txt @@ -0,0 +1,3 @@ +flask>=2.0.3 +markdown>=3.3.5 +pygments>=2.11.2 diff --git a/src/static/styles/0-dracula.css b/src/static/styles/0-dracula.css new file mode 100644 index 0000000..4f51a4b --- /dev/null +++ b/src/static/styles/0-dracula.css @@ -0,0 +1,243 @@ +@font-face { + font-family: "Work Sans"; + src: url(WorkSans-Regular.ttf); +} + +@font-face { + font-family: "Work Sans"; + src: url(WorkSans-Bold.ttf); + font-weight: bold; +} + +@font-face { + font-family: "Work Sans"; + src: url(WorkSans-Italic.ttf); + font-style: italic; +} + +@font-face { + font-family: "Work Sans"; + src: url(WorkSans-BoldItalic.ttf); + font-weight: bold; + font-style: italic; +} + + +html { + background-color: #22242e; + font-family: 'Work Sans'; + color: #f8f8f2; +} + +h1 { + color: #50fa7b; +} + +h2 { + color: #50fa7b; +} + +h3 { + color: #50fa7b; +} + +h4 { + color: #50fa7b; +} + +h5 { + color: #50fa7b; +} + +button { + background-color: transparent; + border: none; + color: #8be9fd; + padding: 1px 2px; + text-align: left; + text-decoration: none; + display: inline-block; + font-size: 1em; + font-style: normal; + cursor: pointer; +} + +hr { + border: 3px dotted; +} + +a { + color: #8be9fd; + text-decoration: underline; + font-style: normal; + font-size: 1em; +} + +.topbar { + background-color: #22242e; + border: none; + color: #8be9fd; + text-align: left; + text-decoration: none; + display: block; +} + +.topbutton { + float: right; +} + +.exportlink { + text-decoration: none; + font-style: normal; +} + +.pagetitle { + font-size: 3em; + color: #ff79c6; + float: left; +} + +.tasktitle { + color: #ff79c6; + font-size: 2em; +} + +.tasktime { + color: #6272a4; + font-style: italic; +} + +.backlink { + text-decoration: none; + font-style: normal; +} + + +/* +.title { + background: #44475a; + color: #50fa7b; + font-weight: bold; + font-size: 2em + border-style: none; + border-radius: 1px; + outline: none; + border-width: 1px; +} +*/ + +.text { + width: 100%; + background: #44475a; + color: #f8f8f2; + border-radius: 5px; + border-style: none; + outline: none; + border-width: 1px; + height: 40%; + font-size: 15px; + -webkit-box-shadow: 0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23); +} + +.title { + width: 100%; + background: #44475a; + color: #f8f8f2; + border-radius: 5px; + border-style: none; + outline: none; + border-width: 1px; + height: 25px; + margin: 5px 0px 5px 0px; + font-size: 15px; + -webkit-box-shadow: 0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23); +} + +.rawtext { + white-space: pre-wrap; +} + +/* Syntax highlighting */ +pre { line-height: 125%; } +td.linenos .normal { color: #f1fa8c; background-color: #44475a; padding-left: 5px; padding-right: 5px; } +span.linenos { color: #f1fa8c; background-color: #44475a; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #50fa7b; background-color: #6272a4; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #50fa7b; background-color: #6272a4; padding-left: 5px; padding-right: 5px; } +.codehilite .hll { background-color: #44475a } +.codehilite { background: #282a36; color: #f8f8f2 } +.codehilite .c { color: #6272a4 } /* Comment */ +.codehilite .err { color: #f8f8f2 } /* Error */ +.codehilite .g { color: #f8f8f2 } /* Generic */ +.codehilite .k { color: #ff79c6 } /* Keyword */ +.codehilite .l { color: #f8f8f2 } /* Literal */ +.codehilite .n { color: #f8f8f2 } /* Name */ +.codehilite .o { color: #ff79c6 } /* Operator */ +.codehilite .x { color: #f8f8f2 } /* Other */ +.codehilite .p { color: #f8f8f2 } /* Punctuation */ +.codehilite .ch { color: #6272a4 } /* Comment.Hashbang */ +.codehilite .cm { color: #6272a4 } /* Comment.Multiline */ +.codehilite .cp { color: #ff79c6 } /* Comment.Preproc */ +.codehilite .cpf { color: #6272a4 } /* Comment.PreprocFile */ +.codehilite .c1 { color: #6272a4 } /* Comment.Single */ +.codehilite .cs { color: #6272a4 } /* Comment.Special */ +.codehilite .gd { color: #8b080b } /* Generic.Deleted */ +.codehilite .ge { color: #f8f8f2; text-decoration: underline } /* Generic.Emph */ +.codehilite .gr { color: #f8f8f2 } /* Generic.Error */ +.codehilite .gh { color: #f8f8f2; font-weight: bold } /* Generic.Heading */ +.codehilite .gi { color: #f8f8f2; font-weight: bold } /* Generic.Inserted */ +.codehilite .go { color: #44475a } /* Generic.Output */ +.codehilite .gp { color: #f8f8f2 } /* Generic.Prompt */ +.codehilite .gs { color: #f8f8f2 } /* Generic.Strong */ +.codehilite .gu { color: #f8f8f2; font-weight: bold } /* Generic.Subheading */ +.codehilite .gt { color: #f8f8f2 } /* Generic.Traceback */ +.codehilite .kc { color: #ff79c6 } /* Keyword.Constant */ +.codehilite .kd { color: #8be9fd; font-style: italic } /* Keyword.Declaration */ +.codehilite .kn { color: #ff79c6 } /* Keyword.Namespace */ +.codehilite .kp { color: #ff79c6 } /* Keyword.Pseudo */ +.codehilite .kr { color: #ff79c6 } /* Keyword.Reserved */ +.codehilite .kt { color: #8be9fd } /* Keyword.Type */ +.codehilite .ld { color: #f8f8f2 } /* Literal.Date */ +.codehilite .m { color: #ffb86c } /* Literal.Number */ +.codehilite .s { color: #bd93f9 } /* Literal.String */ +.codehilite .na { color: #50fa7b } /* Name.Attribute */ +.codehilite .nb { color: #8be9fd; font-style: italic } /* Name.Builtin */ +.codehilite .nc { color: #50fa7b } /* Name.Class */ +.codehilite .no { color: #f8f8f2 } /* Name.Constant */ +.codehilite .nd { color: #f8f8f2 } /* Name.Decorator */ +.codehilite .ni { color: #f8f8f2 } /* Name.Entity */ +.codehilite .ne { color: #f8f8f2 } /* Name.Exception */ +.codehilite .nf { color: #50fa7b } /* Name.Function */ +.codehilite .nl { color: #8be9fd; font-style: italic } /* Name.Label */ +.codehilite .nn { color: #f8f8f2 } /* Name.Namespace */ +.codehilite .nx { color: #f8f8f2 } /* Name.Other */ +.codehilite .py { color: #f8f8f2 } /* Name.Property */ +.codehilite .nt { color: #ff79c6 } /* Name.Tag */ +.codehilite .nv { color: #8be9fd; font-style: italic } /* Name.Variable */ +.codehilite .ow { color: #ff79c6 } /* Operator.Word */ +.codehilite .w { color: #f8f8f2 } /* Text.Whitespace */ +.codehilite .mb { color: #ffb86c } /* Literal.Number.Bin */ +.codehilite .mf { color: #ffb86c } /* Literal.Number.Float */ +.codehilite .mh { color: #ffb86c } /* Literal.Number.Hex */ +.codehilite .mi { color: #ffb86c } /* Literal.Number.Integer */ +.codehilite .mo { color: #ffb86c } /* Literal.Number.Oct */ +.codehilite .sa { color: #bd93f9 } /* Literal.String.Affix */ +.codehilite .sb { color: #bd93f9 } /* Literal.String.Backtick */ +.codehilite .sc { color: #bd93f9 } /* Literal.String.Char */ +.codehilite .dl { color: #bd93f9 } /* Literal.String.Delimiter */ +.codehilite .sd { color: #bd93f9 } /* Literal.String.Doc */ +.codehilite .s2 { color: #bd93f9 } /* Literal.String.Double */ +.codehilite .se { color: #bd93f9 } /* Literal.String.Escape */ +.codehilite .sh { color: #bd93f9 } /* Literal.String.Heredoc */ +.codehilite .si { color: #bd93f9 } /* Literal.String.Interpol */ +.codehilite .sx { color: #bd93f9 } /* Literal.String.Other */ +.codehilite .sr { color: #bd93f9 } /* Literal.String.Regex */ +.codehilite .s1 { color: #bd93f9 } /* Literal.String.Single */ +.codehilite .ss { color: #bd93f9 } /* Literal.String.Symbol */ +.codehilite .bp { color: #f8f8f2; font-style: italic } /* Name.Builtin.Pseudo */ +.codehilite .fm { color: #50fa7b } /* Name.Function.Magic */ +.codehilite .vc { color: #8be9fd; font-style: italic } /* Name.Variable.Class */ +.codehilite .vg { color: #8be9fd; font-style: italic } /* Name.Variable.Global */ +.codehilite .vi { color: #8be9fd; font-style: italic } /* Name.Variable.Instance */ +.codehilite .vm { color: #8be9fd; font-style: italic } /* Name.Variable.Magic */ +.codehilite .il { color: #ffb86c } /* Literal.Number.Integer.Long */ + diff --git a/src/static/styles/1-light.css b/src/static/styles/1-light.css new file mode 100644 index 0000000..380618b --- /dev/null +++ b/src/static/styles/1-light.css @@ -0,0 +1,245 @@ +@font-face { + font-family: "Work Sans"; + src: url(WorkSans-Regular.ttf); +} + +@font-face { + font-family: "Work Sans"; + src: url(WorkSans-Bold.ttf); + font-weight: bold; +} + +@font-face { + font-family: "Work Sans"; + src: url(WorkSans-Italic.ttf); + font-style: italic; +} + +@font-face { + font-family: "Work Sans"; + src: url(WorkSans-BoldItalic.ttf); + font-weight: bold; + font-style: italic; +} + + +html { + background-color: #eee8d5; + font-family: 'Work Sans'; + color: #586e75; +} + +h1 { + color: #d33682; +} + +h2 { + color: #d33682; +} + +h3 { + color: #d33682; +} + +h4 { + color: #d33682; +} + +h5 { + color: #d33682; +} + +button { + background-color: transparent; + border: none; + color: #2aa198; + padding: 1px 2px; + text-align: left; + text-decoration: none; + display: inline-block; + font-size: 1em; + font-style: normal; + cursor: pointer; +} + +hr { + border: 3px dotted; +} + +a { + color: #2aa198; + text-decoration: underline; + font-style: normal; + font-size: 1em; +} + +.topbar { + background-color: #eee8d5; + border: none; + color: #586e75; + text-align: left; + text-decoration: none; + font-style: normal; + display: block; +} + +.topbutton { + float: right; + text-decoration: none; + color: #2aa198; +} + +.exportlink { + text-decoration: none; +} + + +.pagetitle { + font-size: 3em; + color: #ff79c6; + float: left; +} + +.backlink { + text-decoration: none; +} + +.tasktitle { + color: #ff79c6; + font-size: 2em; +} + +.tasktime { + color: #6272a4; + font-style: italic; +} + +/* +.title { + background: #44475a; + color: #d33682; + font-weight: bold; + font-size: 2em + border-style: none; + border-radius: 1px; + outline: none; + border-width: 1px; +} +*/ + +.text { + width: 100%; + background: #fdf6e3; + color: #657b83; + border-radius: 5px; + border-style: none; + outline: none; + border-width: 1px; + height: 80%; + font-size: 15px; + -webkit-box-shadow: 0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23); +} + +.title { + width: 100%; + background: #fdf6e3; + color: #657b83; + border-radius: 5px; + border-style: none; + outline: none; + border-width: 1px; + height: 25px; + margin: 5px 0px 5px 0px; + font-size: 15px; + -webkit-box-shadow: 0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23); +} + +.rawtext { + white-space: pre-wrap; +} + +/* Syntax highlighting */ +pre { line-height: 125%; } +td.linenos .normal { color: #93a1a1; background-color: #eee8d5; padding-left: 5px; padding-right: 5px; } +span.linenos { color: #93a1a1; background-color: #eee8d5; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.codehilite .hll { background-color: #eee8d5 } +.codehilite { background: #fdf6e3; color: #657b83 } +.codehilite .c { color: #93a1a1; font-style: italic } /* Comment */ +.codehilite .err { color: #657b83; background-color: #dc322f } /* Error */ +.codehilite .esc { color: #657b83 } /* Escape */ +.codehilite .g { color: #657b83 } /* Generic */ +.codehilite .k { color: #859900 } /* Keyword */ +.codehilite .l { color: #657b83 } /* Literal */ +.codehilite .n { color: #657b83 } /* Name */ +.codehilite .o { color: #93a1a1 } /* Operator */ +.codehilite .x { color: #657b83 } /* Other */ +.codehilite .p { color: #657b83 } /* Punctuation */ +.codehilite .ch { color: #93a1a1; font-style: italic } /* Comment.Hashbang */ +.codehilite .cm { color: #93a1a1; font-style: italic } /* Comment.Multiline */ +.codehilite .cp { color: #d33682 } /* Comment.Preproc */ +.codehilite .cpf { color: #93a1a1 } /* Comment.PreprocFile */ +.codehilite .c1 { color: #93a1a1; font-style: italic } /* Comment.Single */ +.codehilite .cs { color: #93a1a1; font-style: italic } /* Comment.Special */ +.codehilite .gd { color: #dc322f } /* Generic.Deleted */ +.codehilite .ge { color: #657b83; font-style: italic } /* Generic.Emph */ +.codehilite .gr { color: #dc322f } /* Generic.Error */ +.codehilite .gh { color: #657b83; font-weight: bold } /* Generic.Heading */ +.codehilite .gi { color: #859900 } /* Generic.Inserted */ +.codehilite .go { color: #657b83 } /* Generic.Output */ +.codehilite .gp { color: #268bd2; font-weight: bold } /* Generic.Prompt */ +.codehilite .gs { color: #657b83; font-weight: bold } /* Generic.Strong */ +.codehilite .gu { color: #657b83; text-decoration: underline } /* Generic.Subheading */ +.codehilite .gt { color: #268bd2 } /* Generic.Traceback */ +.codehilite .kc { color: #2aa198 } /* Keyword.Constant */ +.codehilite .kd { color: #2aa198 } /* Keyword.Declaration */ +.codehilite .kn { color: #cb4b16 } /* Keyword.Namespace */ +.codehilite .kp { color: #859900 } /* Keyword.Pseudo */ +.codehilite .kr { color: #859900 } /* Keyword.Reserved */ +.codehilite .kt { color: #b58900 } /* Keyword.Type */ +.codehilite .ld { color: #657b83 } /* Literal.Date */ +.codehilite .m { color: #2aa198 } /* Literal.Number */ +.codehilite .s { color: #2aa198 } /* Literal.String */ +.codehilite .na { color: #657b83 } /* Name.Attribute */ +.codehilite .nb { color: #268bd2 } /* Name.Builtin */ +.codehilite .nc { color: #268bd2 } /* Name.Class */ +.codehilite .no { color: #268bd2 } /* Name.Constant */ +.codehilite .nd { color: #268bd2 } /* Name.Decorator */ +.codehilite .ni { color: #268bd2 } /* Name.Entity */ +.codehilite .ne { color: #268bd2 } /* Name.Exception */ +.codehilite .nf { color: #268bd2 } /* Name.Function */ +.codehilite .nl { color: #268bd2 } /* Name.Label */ +.codehilite .nn { color: #268bd2 } /* Name.Namespace */ +.codehilite .nx { color: #657b83 } /* Name.Other */ +.codehilite .py { color: #657b83 } /* Name.Property */ +.codehilite .nt { color: #268bd2 } /* Name.Tag */ +.codehilite .nv { color: #268bd2 } /* Name.Variable */ +.codehilite .ow { color: #859900 } /* Operator.Word */ +.codehilite .w { color: #657b83 } /* Text.Whitespace */ +.codehilite .mb { color: #2aa198 } /* Literal.Number.Bin */ +.codehilite .mf { color: #2aa198 } /* Literal.Number.Float */ +.codehilite .mh { color: #2aa198 } /* Literal.Number.Hex */ +.codehilite .mi { color: #2aa198 } /* Literal.Number.Integer */ +.codehilite .mo { color: #2aa198 } /* Literal.Number.Oct */ +.codehilite .sa { color: #2aa198 } /* Literal.String.Affix */ +.codehilite .sb { color: #2aa198 } /* Literal.String.Backtick */ +.codehilite .sc { color: #2aa198 } /* Literal.String.Char */ +.codehilite .dl { color: #2aa198 } /* Literal.String.Delimiter */ +.codehilite .sd { color: #93a1a1 } /* Literal.String.Doc */ +.codehilite .s2 { color: #2aa198 } /* Literal.String.Double */ +.codehilite .se { color: #2aa198 } /* Literal.String.Escape */ +.codehilite .sh { color: #2aa198 } /* Literal.String.Heredoc */ +.codehilite .si { color: #2aa198 } /* Literal.String.Interpol */ +.codehilite .sx { color: #2aa198 } /* Literal.String.Other */ +.codehilite .sr { color: #cb4b16 } /* Literal.String.Regex */ +.codehilite .s1 { color: #2aa198 } /* Literal.String.Single */ +.codehilite .ss { color: #2aa198 } /* Literal.String.Symbol */ +.codehilite .bp { color: #268bd2 } /* Name.Builtin.Pseudo */ +.codehilite .fm { color: #268bd2 } /* Name.Function.Magic */ +.codehilite .vc { color: #268bd2 } /* Name.Variable.Class */ +.codehilite .vg { color: #268bd2 } /* Name.Variable.Global */ +.codehilite .vi { color: #268bd2 } /* Name.Variable.Instance */ +.codehilite .vm { color: #268bd2 } /* Name.Variable.Magic */ +.codehilite .il { color: #2aa198 } /* Literal.Number.Integer.Long */ + diff --git a/src/static/styles/WorkSans-Bold.ttf b/src/static/styles/WorkSans-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8a57a7f2ebef5001c3b3b9473019d4e05001d5a6 GIT binary patch literal 192548 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 z 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

    $ ~/sqtasks

    +
    + +
    +
    + + + + + + +
    Note : you can drag the textbox to make it bigger.
    + + + You are editing {{ tasknumber }} which has status {{ taskdonemark }}
    + +
    + {{ nr }} +
    + + + + + diff --git a/src/templates/export.html b/src/templates/export.html new file mode 100644 index 0000000..4048d30 --- /dev/null +++ b/src/templates/export.html @@ -0,0 +1,17 @@ + + + + + + sqtasks + + +
    +{{ rawtasks }} +
    + + diff --git a/src/templates/homepage.html b/src/templates/homepage.html new file mode 100644 index 0000000..a682411 --- /dev/null +++ b/src/templates/homepage.html @@ -0,0 +1,38 @@ + + + + + + sqtasks + + +
    +
    +
    + + +
    + +
    Note : you can drag the textbox to make it bigger. Scroll down to see your previous tasks.
    +
    +
    +

    Todo

    + {{ ntodo }} +

    Done

    + {{ ndone }} + + +
    +
    +
    +

    + You've reached the bottom. Made by Squip, 2022. +

    +
    + + + diff --git a/src/templates/read.html b/src/templates/read.html new file mode 100644 index 0000000..f2d5d85 --- /dev/null +++ b/src/templates/read.html @@ -0,0 +1,20 @@ + + + + + + sqtasks + + + {{ task }} + +
    +
    +
    +

    + You've reached the bottom. Made by Squip, 2022. +

    +
    + + + diff --git a/ssdark.png b/ssdark.png new file mode 100644 index 0000000000000000000000000000000000000000..95e846da19025f437b1ee1f3ad5bcfb48b23d3cc GIT binary patch literal 17449 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 E0UZemxBvhE literal 0 HcmV?d00001 diff --git a/sslight.png b/sslight.png new file mode 100644 index 0000000000000000000000000000000000000000..b6ebc68134115c4594685d8d8c8405113bcab295 GIT binary patch literal 16271 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 literal 0 HcmV?d00001

    v|^F_2CvPiPJ9F9}WL1=)u1*s$F#76zHUItnW*3 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 b)H`GW%7MyFCgADZ6Mz(CeIHN>Se5|*s@PTu literal 0 HcmV?d00001 diff --git a/src/static/styles/WorkSans-Regular.ttf b/src/static/styles/WorkSans-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..82072f19713c98aae6ac98ffceb2b9e1805f68dd GIT binary patch literal 192140 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%0DqFW{2Ea7AE$B;M2|0vMD)Ia0PiG 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 T2sWwk2Mhzg4oPP%T=Rbc51qs; literal 0 HcmV?d00001 diff --git a/src/templates/edit.html b/src/templates/edit.html new file mode 100644 index 0000000..339f4ba --- /dev/null +++ b/src/templates/edit.html @@ -0,0 +1,37 @@ + + + + + + sqtasks + + + +