From 4482c687604323affe39ac16fcf69bdb799899df Mon Sep 17 00:00:00 2001 From: abdull461 Date: Sun, 14 May 2023 10:17:10 +0100 Subject: [PATCH 1/3] installed the necessarry packages --- .../site/python3.11/greenlet/greenlet.h | 164 + .../Flask-2.3.2.dist-info/INSTALLER | 1 + .../Flask-2.3.2.dist-info/LICENSE.rst | 28 + .../Flask-2.3.2.dist-info/METADATA | 118 + .../Flask-2.3.2.dist-info/RECORD | 54 + .../Flask-2.3.2.dist-info/REQUESTED | 0 .../site-packages/Flask-2.3.2.dist-info/WHEEL | 5 + .../Flask-2.3.2.dist-info/entry_points.txt | 2 + .../Flask-2.3.2.dist-info/top_level.txt | 1 + .../Flask_Login-0.6.2.dist-info/INSTALLER | 1 + .../Flask_Login-0.6.2.dist-info/LICENSE | 22 + .../Flask_Login-0.6.2.dist-info/METADATA | 183 + .../Flask_Login-0.6.2.dist-info/RECORD | 23 + .../Flask_Login-0.6.2.dist-info/REQUESTED | 0 .../Flask_Login-0.6.2.dist-info/WHEEL | 5 + .../Flask_Login-0.6.2.dist-info/top_level.txt | 1 + .../INSTALLER | 1 + .../Flask_SQLAlchemy-3.0.3.dist-info/METADATA | 107 + .../Flask_SQLAlchemy-3.0.3.dist-info/RECORD | 27 + .../REQUESTED | 0 .../Flask_SQLAlchemy-3.0.3.dist-info/WHEEL | 4 + .../licenses/LICENSE.rst | 28 + .../Jinja2-3.1.2.dist-info/INSTALLER | 1 + .../Jinja2-3.1.2.dist-info/LICENSE.rst | 28 + .../Jinja2-3.1.2.dist-info/METADATA | 113 + .../Jinja2-3.1.2.dist-info/RECORD | 58 + .../Jinja2-3.1.2.dist-info/WHEEL | 5 + .../Jinja2-3.1.2.dist-info/entry_points.txt | 2 + .../Jinja2-3.1.2.dist-info/top_level.txt | 1 + .../MarkupSafe-2.1.2.dist-info/INSTALLER | 1 + .../MarkupSafe-2.1.2.dist-info/LICENSE.rst | 28 + .../MarkupSafe-2.1.2.dist-info/METADATA | 98 + .../MarkupSafe-2.1.2.dist-info/RECORD | 14 + .../MarkupSafe-2.1.2.dist-info/WHEEL | 5 + .../MarkupSafe-2.1.2.dist-info/top_level.txt | 1 + .../SQLAlchemy-2.0.13.dist-info/INSTALLER | 1 + .../SQLAlchemy-2.0.13.dist-info/LICENSE | 19 + .../SQLAlchemy-2.0.13.dist-info/METADATA | 236 + .../SQLAlchemy-2.0.13.dist-info/RECORD | 512 + .../SQLAlchemy-2.0.13.dist-info/REQUESTED | 0 .../SQLAlchemy-2.0.13.dist-info/WHEEL | 5 + .../SQLAlchemy-2.0.13.dist-info/top_level.txt | 1 + .../Werkzeug-2.3.4.dist-info/INSTALLER | 1 + .../Werkzeug-2.3.4.dist-info/LICENSE.rst | 28 + .../Werkzeug-2.3.4.dist-info/METADATA | 120 + .../Werkzeug-2.3.4.dist-info/RECORD | 126 + .../Werkzeug-2.3.4.dist-info/WHEEL | 5 + .../Werkzeug-2.3.4.dist-info/top_level.txt | 1 + .../typing_extensions.cpython-311.pyc | Bin 0 -> 101808 bytes .../site-packages/_distutils_hack/__init__.py | 222 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 11175 bytes .../__pycache__/override.cpython-311.pyc | Bin 0 -> 332 bytes .../site-packages/_distutils_hack/override.py | 1 + .../blinker-1.6.2.dist-info/INSTALLER | 1 + .../blinker-1.6.2.dist-info/LICENSE.rst | 20 + .../blinker-1.6.2.dist-info/METADATA | 63 + .../blinker-1.6.2.dist-info/RECORD | 15 + .../blinker-1.6.2.dist-info/WHEEL | 5 + .../blinker-1.6.2.dist-info/top_level.txt | 1 + .venv/Lib/site-packages/blinker/__init__.py | 19 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 653 bytes .../__pycache__/_saferef.cpython-311.pyc | Bin 0 -> 9965 bytes .../__pycache__/_utilities.cpython-311.pyc | Bin 0 -> 6713 bytes .../blinker/__pycache__/base.cpython-311.pyc | Bin 0 -> 24853 bytes .venv/Lib/site-packages/blinker/_saferef.py | 230 + .venv/Lib/site-packages/blinker/_utilities.py | 142 + .venv/Lib/site-packages/blinker/base.py | 551 ++ .venv/Lib/site-packages/blinker/py.typed | 0 .../click-8.1.3.dist-info/INSTALLER | 1 + .../click-8.1.3.dist-info/LICENSE.rst | 28 + .../click-8.1.3.dist-info/METADATA | 111 + .../click-8.1.3.dist-info/RECORD | 39 + .../site-packages/click-8.1.3.dist-info/WHEEL | 5 + .../click-8.1.3.dist-info/top_level.txt | 1 + .venv/Lib/site-packages/click/__init__.py | 73 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 3693 bytes .../click/__pycache__/_compat.cpython-311.pyc | Bin 0 -> 28456 bytes .../__pycache__/_termui_impl.cpython-311.pyc | Bin 0 -> 32597 bytes .../__pycache__/_textwrap.cpython-311.pyc | Bin 0 -> 2654 bytes .../__pycache__/_winconsole.cpython-311.pyc | Bin 0 -> 13344 bytes .../click/__pycache__/core.cpython-311.pyc | Bin 0 -> 140788 bytes .../__pycache__/decorators.cpython-311.pyc | Bin 0 -> 23514 bytes .../__pycache__/exceptions.cpython-311.pyc | Bin 0 -> 16074 bytes .../__pycache__/formatting.cpython-311.pyc | Bin 0 -> 15699 bytes .../click/__pycache__/globals.cpython-311.pyc | Bin 0 -> 3381 bytes .../click/__pycache__/parser.cpython-311.pyc | Bin 0 -> 23131 bytes .../shell_completion.cpython-311.pyc | Bin 0 -> 23580 bytes .../click/__pycache__/termui.cpython-311.pyc | Bin 0 -> 34685 bytes .../click/__pycache__/testing.cpython-311.pyc | Bin 0 -> 25749 bytes .../click/__pycache__/types.cpython-311.pyc | Bin 0 -> 52838 bytes .../click/__pycache__/utils.cpython-311.pyc | Bin 0 -> 26022 bytes .venv/Lib/site-packages/click/_compat.py | 626 ++ .venv/Lib/site-packages/click/_termui_impl.py | 717 ++ .venv/Lib/site-packages/click/_textwrap.py | 49 + .venv/Lib/site-packages/click/_winconsole.py | 279 + .venv/Lib/site-packages/click/core.py | 2998 ++++++ .venv/Lib/site-packages/click/decorators.py | 497 + .venv/Lib/site-packages/click/exceptions.py | 287 + .venv/Lib/site-packages/click/formatting.py | 301 + .venv/Lib/site-packages/click/globals.py | 68 + .venv/Lib/site-packages/click/parser.py | 529 + .venv/Lib/site-packages/click/py.typed | 0 .../site-packages/click/shell_completion.py | 580 ++ .venv/Lib/site-packages/click/termui.py | 787 ++ .venv/Lib/site-packages/click/testing.py | 479 + .venv/Lib/site-packages/click/types.py | 1073 ++ .venv/Lib/site-packages/click/utils.py | 580 ++ .../colorama-0.4.6.dist-info/INSTALLER | 1 + .../colorama-0.4.6.dist-info/METADATA | 441 + .../colorama-0.4.6.dist-info/RECORD | 31 + .../colorama-0.4.6.dist-info/WHEEL | 5 + .../licenses/LICENSE.txt | 27 + .venv/Lib/site-packages/colorama/__init__.py | 7 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 578 bytes .../colorama/__pycache__/ansi.cpython-311.pyc | Bin 0 -> 4576 bytes .../__pycache__/ansitowin32.cpython-311.pyc | Bin 0 -> 16222 bytes .../__pycache__/initialise.cpython-311.pyc | Bin 0 -> 3939 bytes .../__pycache__/win32.cpython-311.pyc | Bin 0 -> 7927 bytes .../__pycache__/winterm.cpython-311.pyc | Bin 0 -> 9153 bytes .venv/Lib/site-packages/colorama/ansi.py | 102 + .../Lib/site-packages/colorama/ansitowin32.py | 277 + .../Lib/site-packages/colorama/initialise.py | 121 + .../site-packages/colorama/tests/__init__.py | 1 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 209 bytes .../__pycache__/ansi_test.cpython-311.pyc | Bin 0 -> 5854 bytes .../ansitowin32_test.cpython-311.pyc | Bin 0 -> 21521 bytes .../initialise_test.cpython-311.pyc | Bin 0 -> 14148 bytes .../__pycache__/isatty_test.cpython-311.pyc | Bin 0 -> 6713 bytes .../tests/__pycache__/utils.cpython-311.pyc | Bin 0 -> 2888 bytes .../__pycache__/winterm_test.cpython-311.pyc | Bin 0 -> 7241 bytes .../site-packages/colorama/tests/ansi_test.py | 76 + .../colorama/tests/ansitowin32_test.py | 294 + .../colorama/tests/initialise_test.py | 189 + .../colorama/tests/isatty_test.py | 57 + .../Lib/site-packages/colorama/tests/utils.py | 49 + .../colorama/tests/winterm_test.py | 131 + .venv/Lib/site-packages/colorama/win32.py | 180 + .venv/Lib/site-packages/colorama/winterm.py | 195 + .../site-packages/distutils-precedence.pth | 1 + .venv/Lib/site-packages/flask/__init__.py | 102 + .venv/Lib/site-packages/flask/__main__.py | 3 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 4081 bytes .../__pycache__/__main__.cpython-311.pyc | Bin 0 -> 275 bytes .../flask/__pycache__/app.cpython-311.pyc | Bin 0 -> 87102 bytes .../__pycache__/blueprints.cpython-311.pyc | Bin 0 -> 32024 bytes .../flask/__pycache__/cli.cpython-311.pyc | Bin 0 -> 44176 bytes .../flask/__pycache__/config.cpython-311.pyc | Bin 0 -> 16411 bytes .../flask/__pycache__/ctx.cpython-311.pyc | Bin 0 -> 20638 bytes .../__pycache__/debughelpers.cpython-311.pyc | Bin 0 -> 9482 bytes .../flask/__pycache__/globals.cpython-311.pyc | Bin 0 -> 4279 bytes .../flask/__pycache__/helpers.cpython-311.pyc | Bin 0 -> 29796 bytes .../flask/__pycache__/logging.cpython-311.pyc | Bin 0 -> 3463 bytes .../__pycache__/scaffold.cpython-311.pyc | Bin 0 -> 36470 bytes .../__pycache__/sessions.cpython-311.pyc | Bin 0 -> 17351 bytes .../flask/__pycache__/signals.cpython-311.pyc | Bin 0 -> 1979 bytes .../__pycache__/templating.cpython-311.pyc | Bin 0 -> 10610 bytes .../flask/__pycache__/testing.cpython-311.pyc | Bin 0 -> 14159 bytes .../flask/__pycache__/typing.cpython-311.pyc | Bin 0 -> 3447 bytes .../flask/__pycache__/views.cpython-311.pyc | Bin 0 -> 7316 bytes .../__pycache__/wrappers.cpython-311.pyc | Bin 0 -> 6766 bytes .venv/Lib/site-packages/flask/app.py | 2213 +++++ .venv/Lib/site-packages/flask/blueprints.py | 626 ++ .venv/Lib/site-packages/flask/cli.py | 1067 ++ .venv/Lib/site-packages/flask/config.py | 345 + .venv/Lib/site-packages/flask/ctx.py | 440 + .venv/Lib/site-packages/flask/debughelpers.py | 160 + .venv/Lib/site-packages/flask/globals.py | 96 + .venv/Lib/site-packages/flask/helpers.py | 693 ++ .../Lib/site-packages/flask/json/__init__.py | 170 + .../json/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 6890 bytes .../json/__pycache__/provider.cpython-311.pyc | Bin 0 -> 9997 bytes .../json/__pycache__/tag.cpython-311.pyc | Bin 0 -> 15599 bytes .../Lib/site-packages/flask/json/provider.py | 216 + .venv/Lib/site-packages/flask/json/tag.py | 314 + .venv/Lib/site-packages/flask/logging.py | 76 + .venv/Lib/site-packages/flask/py.typed | 0 .venv/Lib/site-packages/flask/scaffold.py | 923 ++ .venv/Lib/site-packages/flask/sessions.py | 367 + .venv/Lib/site-packages/flask/signals.py | 33 + .venv/Lib/site-packages/flask/templating.py | 220 + .venv/Lib/site-packages/flask/testing.py | 282 + .venv/Lib/site-packages/flask/typing.py | 82 + .venv/Lib/site-packages/flask/views.py | 190 + .venv/Lib/site-packages/flask/wrappers.py | 173 + .../site-packages/flask_login/__about__.py | 10 + .../Lib/site-packages/flask_login/__init__.py | 94 + .../__pycache__/__about__.cpython-311.pyc | Bin 0 -> 689 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 3112 bytes .../__pycache__/config.cpython-311.pyc | Bin 0 -> 930 bytes .../__pycache__/login_manager.cpython-311.pyc | Bin 0 -> 23003 bytes .../__pycache__/mixins.cpython-311.pyc | Bin 0 -> 3262 bytes .../__pycache__/signals.cpython-311.pyc | Bin 0 -> 1855 bytes .../__pycache__/test_client.cpython-311.pyc | Bin 0 -> 1491 bytes .../__pycache__/utils.cpython-311.pyc | Bin 0 -> 18870 bytes .venv/Lib/site-packages/flask_login/config.py | 55 + .../flask_login/login_manager.py | 543 ++ .venv/Lib/site-packages/flask_login/mixins.py | 65 + .../Lib/site-packages/flask_login/signals.py | 61 + .../site-packages/flask_login/test_client.py | 19 + .venv/Lib/site-packages/flask_login/utils.py | 417 + .../flask_sqlalchemy/__init__.py | 46 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 1931 bytes .../__pycache__/cli.cpython-311.pyc | Bin 0 -> 1153 bytes .../__pycache__/extension.cpython-311.pyc | Bin 0 -> 42019 bytes .../__pycache__/model.cpython-311.pyc | Bin 0 -> 10148 bytes .../__pycache__/pagination.cpython-311.pyc | Bin 0 -> 14786 bytes .../__pycache__/query.cpython-311.pyc | Bin 0 -> 4893 bytes .../record_queries.cpython-311.pyc | Bin 0 -> 6355 bytes .../__pycache__/session.cpython-311.pyc | Bin 0 -> 4617 bytes .../__pycache__/table.cpython-311.pyc | Bin 0 -> 1893 bytes .../track_modifications.cpython-311.pyc | Bin 0 -> 4109 bytes .../Lib/site-packages/flask_sqlalchemy/cli.py | 16 + .../flask_sqlalchemy/extension.py | 1005 ++ .../site-packages/flask_sqlalchemy/model.py | 214 + .../flask_sqlalchemy/pagination.py | 360 + .../site-packages/flask_sqlalchemy/py.typed | 0 .../site-packages/flask_sqlalchemy/query.py | 106 + .../flask_sqlalchemy/record_queries.py | 141 + .../site-packages/flask_sqlalchemy/session.py | 102 + .../site-packages/flask_sqlalchemy/table.py | 39 + .../flask_sqlalchemy/track_modifications.py | 88 + .../greenlet-2.0.2.dist-info/AUTHORS | 51 + .../greenlet-2.0.2.dist-info/INSTALLER | 1 + .../greenlet-2.0.2.dist-info/LICENSE | 30 + .../greenlet-2.0.2.dist-info/LICENSE.PSF | 47 + .../greenlet-2.0.2.dist-info/METADATA | 106 + .../greenlet-2.0.2.dist-info/RECORD | 91 + .../greenlet-2.0.2.dist-info/WHEEL | 5 + .../greenlet-2.0.2.dist-info/top_level.txt | 1 + .venv/Lib/site-packages/greenlet/__init__.py | 71 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 1357 bytes .../greenlet/_greenlet.cp311-win_amd64.pyd | Bin 0 -> 64512 bytes .venv/Lib/site-packages/greenlet/greenlet.cpp | 3256 +++++++ .venv/Lib/site-packages/greenlet/greenlet.h | 164 + .../greenlet/greenlet_allocator.hpp | 63 + .../greenlet/greenlet_compiler_compat.hpp | 132 + .../greenlet/greenlet_cpython_compat.hpp | 165 + .../greenlet/greenlet_exceptions.hpp | 106 + .../greenlet/greenlet_greenlet.hpp | 1272 +++ .../greenlet/greenlet_internal.hpp | 106 + .../site-packages/greenlet/greenlet_refs.hpp | 1062 ++ .../greenlet/greenlet_slp_switch.hpp | 117 + .../greenlet/greenlet_thread_state.hpp | 561 ++ .../greenlet_thread_state_dict_cleanup.hpp | 118 + .../greenlet/greenlet_thread_support.hpp | 144 + .../greenlet/platform/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 212 bytes .../platform/setup_switch_x64_masm.cmd | 2 + .../greenlet/platform/switch_aarch64_gcc.h | 78 + .../greenlet/platform/switch_alpha_unix.h | 30 + .../greenlet/platform/switch_amd64_unix.h | 87 + .../greenlet/platform/switch_arm32_gcc.h | 79 + .../greenlet/platform/switch_arm32_ios.h | 67 + .../greenlet/platform/switch_arm64_masm.asm | 53 + .../greenlet/platform/switch_arm64_masm.obj | Bin 0 -> 746 bytes .../greenlet/platform/switch_arm64_msvc.h | 17 + .../greenlet/platform/switch_csky_gcc.h | 48 + .../greenlet/platform/switch_m68k_gcc.h | 38 + .../greenlet/platform/switch_mips_unix.h | 64 + .../greenlet/platform/switch_ppc64_aix.h | 103 + .../greenlet/platform/switch_ppc64_linux.h | 105 + .../greenlet/platform/switch_ppc_aix.h | 87 + .../greenlet/platform/switch_ppc_linux.h | 84 + .../greenlet/platform/switch_ppc_macosx.h | 82 + .../greenlet/platform/switch_ppc_unix.h | 82 + .../greenlet/platform/switch_riscv_unix.h | 32 + .../greenlet/platform/switch_s390_unix.h | 87 + .../greenlet/platform/switch_sparc_sun_gcc.h | 92 + .../greenlet/platform/switch_x32_unix.h | 63 + .../greenlet/platform/switch_x64_masm.asm | 111 + .../greenlet/platform/switch_x64_masm.obj | Bin 0 -> 1078 bytes .../greenlet/platform/switch_x64_msvc.h | 60 + .../greenlet/platform/switch_x86_msvc.h | 326 + .../greenlet/platform/switch_x86_unix.h | 105 + .../greenlet/slp_platformselect.h | 65 + .../site-packages/greenlet/tests/__init__.py | 135 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 6412 bytes .../__pycache__/leakcheck.cpython-311.pyc | Bin 0 -> 12786 bytes .../test_contextvars.cpython-311.pyc | Bin 0 -> 18510 bytes .../__pycache__/test_cpp.cpython-311.pyc | Bin 0 -> 3580 bytes .../test_extension_interface.cpython-311.pyc | Bin 0 -> 8587 bytes .../tests/__pycache__/test_gc.cpython-311.pyc | Bin 0 -> 5516 bytes .../test_generator.cpython-311.pyc | Bin 0 -> 3551 bytes .../test_generator_nested.cpython-311.pyc | Bin 0 -> 9405 bytes .../__pycache__/test_greenlet.cpython-311.pyc | Bin 0 -> 74874 bytes .../test_greenlet_trash.cpython-311.pyc | Bin 0 -> 7305 bytes .../__pycache__/test_leaks.cpython-311.pyc | Bin 0 -> 22613 bytes .../test_stack_saved.cpython-311.pyc | Bin 0 -> 1525 bytes .../__pycache__/test_throw.cpython-311.pyc | Bin 0 -> 8944 bytes .../__pycache__/test_tracing.cpython-311.pyc | Bin 0 -> 15408 bytes .../__pycache__/test_version.cpython-311.pyc | Bin 0 -> 2938 bytes .../__pycache__/test_weakref.cpython-311.pyc | Bin 0 -> 3116 bytes .../greenlet/tests/_test_extension.c | 244 + .../tests/_test_extension.cp311-win_amd64.pyd | Bin 0 -> 13312 bytes .../_test_extension_cpp.cp311-win_amd64.pyd | Bin 0 -> 13824 bytes .../greenlet/tests/_test_extension_cpp.cpp | 196 + .../site-packages/greenlet/tests/leakcheck.py | 318 + .../greenlet/tests/test_contextvars.py | 304 + .../site-packages/greenlet/tests/test_cpp.py | 80 + .../tests/test_extension_interface.py | 115 + .../site-packages/greenlet/tests/test_gc.py | 86 + .../greenlet/tests/test_generator.py | 59 + .../greenlet/tests/test_generator_nested.py | 168 + .../greenlet/tests/test_greenlet.py | 1126 +++ .../greenlet/tests/test_greenlet_trash.py | 185 + .../greenlet/tests/test_leaks.py | 448 + .../greenlet/tests/test_stack_saved.py | 19 + .../greenlet/tests/test_throw.py | 129 + .../greenlet/tests/test_tracing.py | 278 + .../greenlet/tests/test_version.py | 41 + .../greenlet/tests/test_weakref.py | 35 + .../itsdangerous-2.1.2.dist-info/INSTALLER | 1 + .../itsdangerous-2.1.2.dist-info/LICENSE.rst | 28 + .../itsdangerous-2.1.2.dist-info/METADATA | 97 + .../itsdangerous-2.1.2.dist-info/RECORD | 23 + .../itsdangerous-2.1.2.dist-info/WHEEL | 5 + .../top_level.txt | 1 + .../site-packages/itsdangerous/__init__.py | 19 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 1164 bytes .../__pycache__/_json.cpython-311.pyc | Bin 0 -> 1402 bytes .../__pycache__/encoding.cpython-311.pyc | Bin 0 -> 2989 bytes .../__pycache__/exc.cpython-311.pyc | Bin 0 -> 5005 bytes .../__pycache__/serializer.cpython-311.pyc | Bin 0 -> 13648 bytes .../__pycache__/signer.cpython-311.pyc | Bin 0 -> 12355 bytes .../__pycache__/timed.cpython-311.pyc | Bin 0 -> 10081 bytes .../__pycache__/url_safe.cpython-311.pyc | Bin 0 -> 4009 bytes .venv/Lib/site-packages/itsdangerous/_json.py | 16 + .../site-packages/itsdangerous/encoding.py | 54 + .venv/Lib/site-packages/itsdangerous/exc.py | 107 + .venv/Lib/site-packages/itsdangerous/py.typed | 0 .../site-packages/itsdangerous/serializer.py | 295 + .../Lib/site-packages/itsdangerous/signer.py | 257 + .venv/Lib/site-packages/itsdangerous/timed.py | 234 + .../site-packages/itsdangerous/url_safe.py | 80 + .venv/Lib/site-packages/jinja2/__init__.py | 37 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 2134 bytes .../__pycache__/_identifier.cpython-311.pyc | Bin 0 -> 2150 bytes .../__pycache__/async_utils.cpython-311.pyc | Bin 0 -> 4651 bytes .../__pycache__/bccache.cpython-311.pyc | Bin 0 -> 20932 bytes .../__pycache__/compiler.cpython-311.pyc | Bin 0 -> 110493 bytes .../__pycache__/constants.cpython-311.pyc | Bin 0 -> 1569 bytes .../jinja2/__pycache__/debug.cpython-311.pyc | Bin 0 -> 6729 bytes .../__pycache__/defaults.cpython-311.pyc | Bin 0 -> 1735 bytes .../__pycache__/environment.cpython-311.pyc | Bin 0 -> 80551 bytes .../__pycache__/exceptions.cpython-311.pyc | Bin 0 -> 8620 bytes .../jinja2/__pycache__/ext.cpython-311.pyc | Bin 0 -> 43199 bytes .../__pycache__/filters.cpython-311.pyc | Bin 0 -> 75897 bytes .../__pycache__/idtracking.cpython-311.pyc | Bin 0 -> 19555 bytes .../jinja2/__pycache__/lexer.cpython-311.pyc | Bin 0 -> 35630 bytes .../__pycache__/loaders.cpython-311.pyc | Bin 0 -> 33088 bytes .../jinja2/__pycache__/meta.cpython-311.pyc | Bin 0 -> 5714 bytes .../__pycache__/nativetypes.cpython-311.pyc | Bin 0 -> 7976 bytes .../jinja2/__pycache__/nodes.cpython-311.pyc | Bin 0 -> 64495 bytes .../__pycache__/optimizer.cpython-311.pyc | Bin 0 -> 2865 bytes .../jinja2/__pycache__/parser.cpython-311.pyc | Bin 0 -> 59309 bytes .../__pycache__/runtime.cpython-311.pyc | Bin 0 -> 50661 bytes .../__pycache__/sandbox.cpython-311.pyc | Bin 0 -> 18833 bytes .../jinja2/__pycache__/tests.cpython-311.pyc | Bin 0 -> 9256 bytes .../jinja2/__pycache__/utils.cpython-311.pyc | Bin 0 -> 37071 bytes .../__pycache__/visitor.cpython-311.pyc | Bin 0 -> 5725 bytes .venv/Lib/site-packages/jinja2/_identifier.py | 6 + .venv/Lib/site-packages/jinja2/async_utils.py | 84 + .venv/Lib/site-packages/jinja2/bccache.py | 406 + .venv/Lib/site-packages/jinja2/compiler.py | 1957 ++++ .venv/Lib/site-packages/jinja2/constants.py | 20 + .venv/Lib/site-packages/jinja2/debug.py | 191 + .venv/Lib/site-packages/jinja2/defaults.py | 48 + .venv/Lib/site-packages/jinja2/environment.py | 1667 ++++ .venv/Lib/site-packages/jinja2/exceptions.py | 166 + .venv/Lib/site-packages/jinja2/ext.py | 859 ++ .venv/Lib/site-packages/jinja2/filters.py | 1840 ++++ .venv/Lib/site-packages/jinja2/idtracking.py | 318 + .venv/Lib/site-packages/jinja2/lexer.py | 866 ++ .venv/Lib/site-packages/jinja2/loaders.py | 661 ++ .venv/Lib/site-packages/jinja2/meta.py | 111 + .venv/Lib/site-packages/jinja2/nativetypes.py | 130 + .venv/Lib/site-packages/jinja2/nodes.py | 1204 +++ .venv/Lib/site-packages/jinja2/optimizer.py | 47 + .venv/Lib/site-packages/jinja2/parser.py | 1032 ++ .venv/Lib/site-packages/jinja2/py.typed | 0 .venv/Lib/site-packages/jinja2/runtime.py | 1053 ++ .venv/Lib/site-packages/jinja2/sandbox.py | 428 + .venv/Lib/site-packages/jinja2/tests.py | 255 + .venv/Lib/site-packages/jinja2/utils.py | 755 ++ .venv/Lib/site-packages/jinja2/visitor.py | 92 + .../Lib/site-packages/markupsafe/__init__.py | 295 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 18380 bytes .../__pycache__/_native.cpython-311.pyc | Bin 0 -> 2752 bytes .venv/Lib/site-packages/markupsafe/_native.py | 63 + .../Lib/site-packages/markupsafe/_speedups.c | 320 + .../markupsafe/_speedups.cp311-win_amd64.pyd | Bin 0 -> 15872 bytes .../site-packages/markupsafe/_speedups.pyi | 9 + .venv/Lib/site-packages/markupsafe/py.typed | 0 .../pip-22.3.1.dist-info/INSTALLER | 1 + .../pip-22.3.1.dist-info/LICENSE.txt | 20 + .../pip-22.3.1.dist-info/METADATA | 88 + .../site-packages/pip-22.3.1.dist-info/RECORD | 992 ++ .../pip-22.3.1.dist-info/REQUESTED | 0 .../site-packages/pip-22.3.1.dist-info/WHEEL | 5 + .../pip-22.3.1.dist-info/entry_points.txt | 4 + .../pip-22.3.1.dist-info/top_level.txt | 1 + .venv/Lib/site-packages/pip/__init__.py | 13 + .venv/Lib/site-packages/pip/__main__.py | 31 + .venv/Lib/site-packages/pip/__pip-runner__.py | 50 + .../pip/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 787 bytes .../pip/__pycache__/__main__.cpython-311.pyc | Bin 0 -> 1096 bytes .../__pip-runner__.cpython-311.pyc | Bin 0 -> 2524 bytes .../site-packages/pip/_internal/__init__.py | 19 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 970 bytes .../__pycache__/build_env.cpython-311.pyc | Bin 0 -> 15917 bytes .../__pycache__/cache.cpython-311.pyc | Bin 0 -> 14715 bytes .../__pycache__/configuration.cpython-311.pyc | Bin 0 -> 19246 bytes .../__pycache__/exceptions.cpython-311.pyc | Bin 0 -> 33950 bytes .../__pycache__/main.cpython-311.pyc | Bin 0 -> 770 bytes .../__pycache__/pyproject.cpython-311.pyc | Bin 0 -> 5542 bytes .../self_outdated_check.cpython-311.pyc | Bin 0 -> 11184 bytes .../__pycache__/wheel_builder.cpython-311.pyc | Bin 0 -> 16010 bytes .../site-packages/pip/_internal/build_env.py | 310 + .../Lib/site-packages/pip/_internal/cache.py | 293 + .../pip/_internal/cli/__init__.py | 4 + .../cli/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 305 bytes .../autocompletion.cpython-311.pyc | Bin 0 -> 10095 bytes .../__pycache__/base_command.cpython-311.pyc | Bin 0 -> 11093 bytes .../__pycache__/cmdoptions.cpython-311.pyc | Bin 0 -> 32859 bytes .../command_context.cpython-311.pyc | Bin 0 -> 2127 bytes .../cli/__pycache__/main.cpython-311.pyc | Bin 0 -> 2382 bytes .../__pycache__/main_parser.cpython-311.pyc | Bin 0 -> 5541 bytes .../cli/__pycache__/parser.cpython-311.pyc | Bin 0 -> 17042 bytes .../__pycache__/progress_bars.cpython-311.pyc | Bin 0 -> 3189 bytes .../__pycache__/req_command.cpython-311.pyc | Bin 0 -> 20154 bytes .../cli/__pycache__/spinners.cpython-311.pyc | Bin 0 -> 8854 bytes .../__pycache__/status_codes.cpython-311.pyc | Bin 0 -> 393 bytes .../pip/_internal/cli/autocompletion.py | 171 + .../pip/_internal/cli/base_command.py | 216 + .../pip/_internal/cli/cmdoptions.py | 1049 ++ .../pip/_internal/cli/command_context.py | 27 + .../site-packages/pip/_internal/cli/main.py | 70 + .../pip/_internal/cli/main_parser.py | 134 + .../site-packages/pip/_internal/cli/parser.py | 294 + .../pip/_internal/cli/progress_bars.py | 68 + .../pip/_internal/cli/req_command.py | 502 + .../pip/_internal/cli/spinners.py | 159 + .../pip/_internal/cli/status_codes.py | 6 + .../pip/_internal/commands/__init__.py | 132 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 4473 bytes .../__pycache__/cache.cpython-311.pyc | Bin 0 -> 10572 bytes .../__pycache__/check.cpython-311.pyc | Bin 0 -> 2323 bytes .../__pycache__/completion.cpython-311.pyc | Bin 0 -> 5485 bytes .../__pycache__/configuration.cpython-311.pyc | Bin 0 -> 14914 bytes .../__pycache__/debug.cpython-311.pyc | Bin 0 -> 11949 bytes .../__pycache__/download.cpython-311.pyc | Bin 0 -> 7829 bytes .../__pycache__/freeze.cpython-311.pyc | Bin 0 -> 4159 bytes .../commands/__pycache__/hash.cpython-311.pyc | Bin 0 -> 3375 bytes .../commands/__pycache__/help.cpython-311.pyc | Bin 0 -> 1987 bytes .../__pycache__/index.cpython-311.pyc | Bin 0 -> 7776 bytes .../__pycache__/inspect.cpython-311.pyc | Bin 0 -> 4682 bytes .../__pycache__/install.cpython-311.pyc | Bin 0 -> 35120 bytes .../commands/__pycache__/list.cpython-311.pyc | Bin 0 -> 17167 bytes .../__pycache__/search.cpython-311.pyc | Bin 0 -> 8969 bytes .../commands/__pycache__/show.cpython-311.pyc | Bin 0 -> 11076 bytes .../__pycache__/uninstall.cpython-311.pyc | Bin 0 -> 4886 bytes .../__pycache__/wheel.cpython-311.pyc | Bin 0 -> 9969 bytes .../pip/_internal/commands/cache.py | 223 + .../pip/_internal/commands/check.py | 53 + .../pip/_internal/commands/completion.py | 126 + .../pip/_internal/commands/configuration.py | 282 + .../pip/_internal/commands/debug.py | 199 + .../pip/_internal/commands/download.py | 149 + .../pip/_internal/commands/freeze.py | 97 + .../pip/_internal/commands/hash.py | 59 + .../pip/_internal/commands/help.py | 41 + .../pip/_internal/commands/index.py | 138 + .../pip/_internal/commands/inspect.py | 97 + .../pip/_internal/commands/install.py | 860 ++ .../pip/_internal/commands/list.py | 365 + .../pip/_internal/commands/search.py | 174 + .../pip/_internal/commands/show.py | 183 + .../pip/_internal/commands/uninstall.py | 106 + .../pip/_internal/commands/wheel.py | 203 + .../pip/_internal/configuration.py | 374 + .../pip/_internal/distributions/__init__.py | 21 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 1055 bytes .../__pycache__/base.cpython-311.pyc | Bin 0 -> 2427 bytes .../__pycache__/installed.cpython-311.pyc | Bin 0 -> 1564 bytes .../__pycache__/sdist.cpython-311.pyc | Bin 0 -> 8966 bytes .../__pycache__/wheel.cpython-311.pyc | Bin 0 -> 2158 bytes .../pip/_internal/distributions/base.py | 39 + .../pip/_internal/distributions/installed.py | 23 + .../pip/_internal/distributions/sdist.py | 150 + .../pip/_internal/distributions/wheel.py | 34 + .../site-packages/pip/_internal/exceptions.py | 660 ++ .../pip/_internal/index/__init__.py | 2 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 259 bytes .../__pycache__/collector.cpython-311.pyc | Bin 0 -> 24565 bytes .../package_finder.cpython-311.pyc | Bin 0 -> 43628 bytes .../index/__pycache__/sources.cpython-311.pyc | Bin 0 -> 11041 bytes .../pip/_internal/index/collector.py | 505 + .../pip/_internal/index/package_finder.py | 1025 ++ .../pip/_internal/index/sources.py | 224 + .../pip/_internal/locations/__init__.py | 528 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 20684 bytes .../__pycache__/_distutils.cpython-311.pyc | Bin 0 -> 7925 bytes .../__pycache__/_sysconfig.cpython-311.pyc | Bin 0 -> 9257 bytes .../__pycache__/base.cpython-311.pyc | Bin 0 -> 4051 bytes .../pip/_internal/locations/_distutils.py | 180 + .../pip/_internal/locations/_sysconfig.py | 218 + .../pip/_internal/locations/base.py | 81 + .venv/Lib/site-packages/pip/_internal/main.py | 12 + .../pip/_internal/metadata/__init__.py | 127 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 6430 bytes .../__pycache__/_json.cpython-311.pyc | Bin 0 -> 3584 bytes .../metadata/__pycache__/base.cpython-311.pyc | Bin 0 -> 38029 bytes .../__pycache__/pkg_resources.cpython-311.pyc | Bin 0 -> 16877 bytes .../pip/_internal/metadata/_json.py | 84 + .../pip/_internal/metadata/base.py | 688 ++ .../_internal/metadata/importlib/__init__.py | 4 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 376 bytes .../__pycache__/_compat.cpython-311.pyc | Bin 0 -> 3583 bytes .../__pycache__/_dists.cpython-311.pyc | Bin 0 -> 14599 bytes .../__pycache__/_envs.cpython-311.pyc | Bin 0 -> 12437 bytes .../_internal/metadata/importlib/_compat.py | 55 + .../_internal/metadata/importlib/_dists.py | 224 + .../pip/_internal/metadata/importlib/_envs.py | 188 + .../pip/_internal/metadata/pkg_resources.py | 270 + .../pip/_internal/models/__init__.py | 2 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 293 bytes .../__pycache__/candidate.cpython-311.pyc | Bin 0 -> 2112 bytes .../__pycache__/direct_url.cpython-311.pyc | Bin 0 -> 11617 bytes .../format_control.cpython-311.pyc | Bin 0 -> 4676 bytes .../models/__pycache__/index.cpython-311.pyc | Bin 0 -> 1918 bytes .../installation_report.cpython-311.pyc | Bin 0 -> 2632 bytes .../models/__pycache__/link.cpython-311.pyc | Bin 0 -> 25028 bytes .../models/__pycache__/scheme.cpython-311.pyc | Bin 0 -> 1284 bytes .../__pycache__/search_scope.cpython-311.pyc | Bin 0 -> 5847 bytes .../selection_prefs.cpython-311.pyc | Bin 0 -> 2015 bytes .../__pycache__/target_python.cpython-311.pyc | Bin 0 -> 4777 bytes .../models/__pycache__/wheel.cpython-311.pyc | Bin 0 -> 6440 bytes .../pip/_internal/models/candidate.py | 34 + .../pip/_internal/models/direct_url.py | 212 + .../pip/_internal/models/format_control.py | 80 + .../pip/_internal/models/index.py | 28 + .../_internal/models/installation_report.py | 53 + .../pip/_internal/models/link.py | 507 + .../pip/_internal/models/scheme.py | 31 + .../pip/_internal/models/search_scope.py | 133 + .../pip/_internal/models/selection_prefs.py | 51 + .../pip/_internal/models/target_python.py | 110 + .../pip/_internal/models/wheel.py | 92 + .../pip/_internal/network/__init__.py | 2 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 281 bytes .../network/__pycache__/auth.cpython-311.pyc | Bin 0 -> 12200 bytes .../network/__pycache__/cache.cpython-311.pyc | Bin 0 -> 5204 bytes .../__pycache__/download.cpython-311.pyc | Bin 0 -> 9596 bytes .../__pycache__/lazy_wheel.cpython-311.pyc | Bin 0 -> 13042 bytes .../__pycache__/session.cpython-311.pyc | Bin 0 -> 21309 bytes .../network/__pycache__/utils.cpython-311.pyc | Bin 0 -> 2430 bytes .../__pycache__/xmlrpc.cpython-311.pyc | Bin 0 -> 3209 bytes .../pip/_internal/network/auth.py | 323 + .../pip/_internal/network/cache.py | 69 + .../pip/_internal/network/download.py | 186 + .../pip/_internal/network/lazy_wheel.py | 210 + .../pip/_internal/network/session.py | 518 + .../pip/_internal/network/utils.py | 96 + .../pip/_internal/network/xmlrpc.py | 60 + .../pip/_internal/operations/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 219 bytes .../__pycache__/check.cpython-311.pyc | Bin 0 -> 6631 bytes .../__pycache__/freeze.cpython-311.pyc | Bin 0 -> 11615 bytes .../__pycache__/prepare.cpython-311.pyc | Bin 0 -> 26399 bytes .../_internal/operations/build/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 225 bytes .../__pycache__/build_tracker.cpython-311.pyc | Bin 0 -> 8148 bytes .../__pycache__/metadata.cpython-311.pyc | Bin 0 -> 2290 bytes .../metadata_editable.cpython-311.pyc | Bin 0 -> 2326 bytes .../metadata_legacy.cpython-311.pyc | Bin 0 -> 3732 bytes .../build/__pycache__/wheel.cpython-311.pyc | Bin 0 -> 1956 bytes .../wheel_editable.cpython-311.pyc | Bin 0 -> 2400 bytes .../__pycache__/wheel_legacy.cpython-311.pyc | Bin 0 -> 4513 bytes .../operations/build/build_tracker.py | 124 + .../_internal/operations/build/metadata.py | 39 + .../operations/build/metadata_editable.py | 41 + .../operations/build/metadata_legacy.py | 74 + .../pip/_internal/operations/build/wheel.py | 37 + .../operations/build/wheel_editable.py | 46 + .../operations/build/wheel_legacy.py | 102 + .../pip/_internal/operations/check.py | 149 + .../pip/_internal/operations/freeze.py | 254 + .../_internal/operations/install/__init__.py | 2 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 293 bytes .../editable_legacy.cpython-311.pyc | Bin 0 -> 2289 bytes .../__pycache__/legacy.cpython-311.pyc | Bin 0 -> 6129 bytes .../install/__pycache__/wheel.cpython-311.pyc | Bin 0 -> 40015 bytes .../operations/install/editable_legacy.py | 47 + .../_internal/operations/install/legacy.py | 120 + .../pip/_internal/operations/install/wheel.py | 738 ++ .../pip/_internal/operations/prepare.py | 667 ++ .../site-packages/pip/_internal/pyproject.py | 175 + .../pip/_internal/req/__init__.py | 94 + .../req/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 4465 bytes .../__pycache__/constructors.cpython-311.pyc | Bin 0 -> 20724 bytes .../req/__pycache__/req_file.cpython-311.pyc | Bin 0 -> 22453 bytes .../__pycache__/req_install.cpython-311.pyc | Bin 0 -> 40303 bytes .../req/__pycache__/req_set.cpython-311.pyc | Bin 0 -> 6021 bytes .../__pycache__/req_uninstall.cpython-311.pyc | Bin 0 -> 37019 bytes .../pip/_internal/req/constructors.py | 501 + .../pip/_internal/req/req_file.py | 544 ++ .../pip/_internal/req/req_install.py | 942 ++ .../pip/_internal/req/req_set.py | 82 + .../pip/_internal/req/req_uninstall.py | 640 ++ .../pip/_internal/resolution/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 219 bytes .../__pycache__/base.cpython-311.pyc | Bin 0 -> 1390 bytes .../pip/_internal/resolution/base.py | 20 + .../_internal/resolution/legacy/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 226 bytes .../__pycache__/resolver.cpython-311.pyc | Bin 0 -> 23812 bytes .../_internal/resolution/legacy/resolver.py | 600 ++ .../resolution/resolvelib/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 230 bytes .../__pycache__/base.cpython-311.pyc | Bin 0 -> 9643 bytes .../__pycache__/candidates.cpython-311.pyc | Bin 0 -> 28853 bytes .../__pycache__/factory.cpython-311.pyc | Bin 0 -> 31997 bytes .../found_candidates.cpython-311.pyc | Bin 0 -> 6778 bytes .../__pycache__/provider.cpython-311.pyc | Bin 0 -> 11072 bytes .../__pycache__/reporter.cpython-311.pyc | Bin 0 -> 4675 bytes .../__pycache__/requirements.cpython-311.pyc | Bin 0 -> 11140 bytes .../__pycache__/resolver.cpython-311.pyc | Bin 0 -> 12327 bytes .../_internal/resolution/resolvelib/base.py | 141 + .../resolution/resolvelib/candidates.py | 556 ++ .../resolution/resolvelib/factory.py | 731 ++ .../resolution/resolvelib/found_candidates.py | 155 + .../resolution/resolvelib/provider.py | 248 + .../resolution/resolvelib/reporter.py | 68 + .../resolution/resolvelib/requirements.py | 166 + .../resolution/resolvelib/resolver.py | 296 + .../pip/_internal/self_outdated_check.py | 239 + .../pip/_internal/utils/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 214 bytes .../utils/__pycache__/_log.cpython-311.pyc | Bin 0 -> 2035 bytes .../utils/__pycache__/appdirs.cpython-311.pyc | Bin 0 -> 2573 bytes .../utils/__pycache__/compat.cpython-311.pyc | Bin 0 -> 2281 bytes .../compatibility_tags.cpython-311.pyc | Bin 0 -> 6773 bytes .../__pycache__/datetime.cpython-311.pyc | Bin 0 -> 731 bytes .../__pycache__/deprecation.cpython-311.pyc | Bin 0 -> 7104 bytes .../direct_url_helpers.cpython-311.pyc | Bin 0 -> 3737 bytes .../distutils_args.cpython-311.pyc | Bin 0 -> 1481 bytes .../__pycache__/egg_link.cpython-311.pyc | Bin 0 -> 3233 bytes .../__pycache__/encoding.cpython-311.pyc | Bin 0 -> 2337 bytes .../__pycache__/entrypoints.cpython-311.pyc | Bin 0 -> 4259 bytes .../__pycache__/filesystem.cpython-311.pyc | Bin 0 -> 8244 bytes .../__pycache__/filetypes.cpython-311.pyc | Bin 0 -> 1330 bytes .../utils/__pycache__/glibc.cpython-311.pyc | Bin 0 -> 2573 bytes .../utils/__pycache__/hashes.cpython-311.pyc | Bin 0 -> 8351 bytes .../inject_securetransport.cpython-311.pyc | Bin 0 -> 1348 bytes .../utils/__pycache__/logging.cpython-311.pyc | Bin 0 -> 15473 bytes .../utils/__pycache__/misc.cpython-311.pyc | Bin 0 -> 35787 bytes .../utils/__pycache__/models.cpython-311.pyc | Bin 0 -> 2954 bytes .../__pycache__/packaging.cpython-311.pyc | Bin 0 -> 2821 bytes .../setuptools_build.cpython-311.pyc | Bin 0 -> 6118 bytes .../__pycache__/subprocess.cpython-311.pyc | Bin 0 -> 9905 bytes .../__pycache__/temp_dir.cpython-311.pyc | Bin 0 -> 11435 bytes .../__pycache__/unpacking.cpython-311.pyc | Bin 0 -> 12910 bytes .../utils/__pycache__/urls.cpython-311.pyc | Bin 0 -> 2707 bytes .../__pycache__/virtualenv.cpython-311.pyc | Bin 0 -> 4954 bytes .../utils/__pycache__/wheel.cpython-311.pyc | Bin 0 -> 7124 bytes .../site-packages/pip/_internal/utils/_log.py | 38 + .../pip/_internal/utils/appdirs.py | 52 + .../pip/_internal/utils/compat.py | 63 + .../pip/_internal/utils/compatibility_tags.py | 165 + .../pip/_internal/utils/datetime.py | 11 + .../pip/_internal/utils/deprecation.py | 188 + .../pip/_internal/utils/direct_url_helpers.py | 87 + .../pip/_internal/utils/distutils_args.py | 43 + .../pip/_internal/utils/egg_link.py | 75 + .../pip/_internal/utils/encoding.py | 36 + .../pip/_internal/utils/entrypoints.py | 84 + .../pip/_internal/utils/filesystem.py | 153 + .../pip/_internal/utils/filetypes.py | 27 + .../pip/_internal/utils/glibc.py | 88 + .../pip/_internal/utils/hashes.py | 144 + .../_internal/utils/inject_securetransport.py | 35 + .../pip/_internal/utils/logging.py | 348 + .../site-packages/pip/_internal/utils/misc.py | 723 ++ .../pip/_internal/utils/models.py | 39 + .../pip/_internal/utils/packaging.py | 57 + .../pip/_internal/utils/setuptools_build.py | 195 + .../pip/_internal/utils/subprocess.py | 260 + .../pip/_internal/utils/temp_dir.py | 246 + .../pip/_internal/utils/unpacking.py | 257 + .../site-packages/pip/_internal/utils/urls.py | 62 + .../pip/_internal/utils/virtualenv.py | 104 + .../pip/_internal/utils/wheel.py | 136 + .../pip/_internal/vcs/__init__.py | 15 + .../vcs/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 649 bytes .../vcs/__pycache__/bazaar.cpython-311.pyc | Bin 0 -> 5874 bytes .../vcs/__pycache__/git.cpython-311.pyc | Bin 0 -> 21538 bytes .../vcs/__pycache__/mercurial.cpython-311.pyc | Bin 0 -> 8720 bytes .../__pycache__/subversion.cpython-311.pyc | Bin 0 -> 14617 bytes .../versioncontrol.cpython-311.pyc | Bin 0 -> 31886 bytes .../site-packages/pip/_internal/vcs/bazaar.py | 112 + .../site-packages/pip/_internal/vcs/git.py | 526 + .../pip/_internal/vcs/mercurial.py | 163 + .../pip/_internal/vcs/subversion.py | 324 + .../pip/_internal/vcs/versioncontrol.py | 705 ++ .../pip/_internal/wheel_builder.py | 382 + .../Lib/site-packages/pip/_vendor/__init__.py | 120 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 5627 bytes .../_vendor/__pycache__/six.cpython-311.pyc | Bin 0 -> 46429 bytes .../typing_extensions.cpython-311.pyc | Bin 0 -> 97459 bytes .../pip/_vendor/cachecontrol/__init__.py | 18 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 856 bytes .../__pycache__/_cmd.cpython-311.pyc | Bin 0 -> 2711 bytes .../__pycache__/adapter.cpython-311.pyc | Bin 0 -> 5518 bytes .../__pycache__/cache.cpython-311.pyc | Bin 0 -> 3792 bytes .../__pycache__/compat.cpython-311.pyc | Bin 0 -> 1149 bytes .../__pycache__/controller.cpython-311.pyc | Bin 0 -> 16464 bytes .../__pycache__/filewrapper.cpython-311.pyc | Bin 0 -> 4251 bytes .../__pycache__/heuristics.cpython-311.pyc | Bin 0 -> 6696 bytes .../__pycache__/serialize.cpython-311.pyc | Bin 0 -> 8411 bytes .../__pycache__/wrapper.cpython-311.pyc | Bin 0 -> 977 bytes .../pip/_vendor/cachecontrol/_cmd.py | 61 + .../pip/_vendor/cachecontrol/adapter.py | 137 + .../pip/_vendor/cachecontrol/cache.py | 65 + .../_vendor/cachecontrol/caches/__init__.py | 9 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 431 bytes .../__pycache__/file_cache.cpython-311.pyc | Bin 0 -> 8414 bytes .../__pycache__/redis_cache.cpython-311.pyc | Bin 0 -> 2511 bytes .../_vendor/cachecontrol/caches/file_cache.py | 188 + .../cachecontrol/caches/redis_cache.py | 39 + .../pip/_vendor/cachecontrol/compat.py | 32 + .../pip/_vendor/cachecontrol/controller.py | 439 + .../pip/_vendor/cachecontrol/filewrapper.py | 111 + .../pip/_vendor/cachecontrol/heuristics.py | 139 + .../pip/_vendor/cachecontrol/serialize.py | 190 + .../pip/_vendor/cachecontrol/wrapper.py | 33 + .../pip/_vendor/certifi/__init__.py | 4 + .../pip/_vendor/certifi/__main__.py | 12 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 356 bytes .../__pycache__/__main__.cpython-311.pyc | Bin 0 -> 757 bytes .../certifi/__pycache__/core.cpython-311.pyc | Bin 0 -> 3379 bytes .../pip/_vendor/certifi/cacert.pem | 4708 +++++++++ .../site-packages/pip/_vendor/certifi/core.py | 108 + .../pip/_vendor/chardet/__init__.py | 93 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 3982 bytes .../__pycache__/big5freq.cpython-311.pyc | Bin 0 -> 27218 bytes .../__pycache__/big5prober.cpython-311.pyc | Bin 0 -> 1628 bytes .../chardistribution.cpython-311.pyc | Bin 0 -> 10410 bytes .../charsetgroupprober.cpython-311.pyc | Bin 0 -> 3944 bytes .../__pycache__/charsetprober.cpython-311.pyc | Bin 0 -> 4758 bytes .../codingstatemachine.cpython-311.pyc | Bin 0 -> 3703 bytes .../__pycache__/cp949prober.cpython-311.pyc | Bin 0 -> 1637 bytes .../chardet/__pycache__/enums.cpython-311.pyc | Bin 0 -> 3267 bytes .../__pycache__/escprober.cpython-311.pyc | Bin 0 -> 4546 bytes .../chardet/__pycache__/escsm.cpython-311.pyc | Bin 0 -> 12415 bytes .../__pycache__/eucjpprober.cpython-311.pyc | Bin 0 -> 4395 bytes .../__pycache__/euckrfreq.cpython-311.pyc | Bin 0 -> 12101 bytes .../__pycache__/euckrprober.cpython-311.pyc | Bin 0 -> 1629 bytes .../__pycache__/euctwfreq.cpython-311.pyc | Bin 0 -> 27223 bytes .../__pycache__/euctwprober.cpython-311.pyc | Bin 0 -> 1629 bytes .../__pycache__/gb2312freq.cpython-311.pyc | Bin 0 -> 19145 bytes .../__pycache__/gb2312prober.cpython-311.pyc | Bin 0 -> 1644 bytes .../__pycache__/hebrewprober.cpython-311.pyc | Bin 0 -> 4958 bytes .../__pycache__/jisfreq.cpython-311.pyc | Bin 0 -> 22174 bytes .../__pycache__/johabfreq.cpython-311.pyc | Bin 0 -> 84678 bytes .../__pycache__/johabprober.cpython-311.pyc | Bin 0 -> 1635 bytes .../__pycache__/jpcntx.cpython-311.pyc | Bin 0 -> 39544 bytes .../langbulgarianmodel.cpython-311.pyc | Bin 0 -> 85852 bytes .../langgreekmodel.cpython-311.pyc | Bin 0 -> 79274 bytes .../langhebrewmodel.cpython-311.pyc | Bin 0 -> 80036 bytes .../langhungarianmodel.cpython-311.pyc | Bin 0 -> 85806 bytes .../langrussianmodel.cpython-311.pyc | Bin 0 -> 108753 bytes .../__pycache__/langthaimodel.cpython-311.pyc | Bin 0 -> 80214 bytes .../langturkishmodel.cpython-311.pyc | Bin 0 -> 80053 bytes .../__pycache__/latin1prober.cpython-311.pyc | Bin 0 -> 7076 bytes .../mbcharsetprober.cpython-311.pyc | Bin 0 -> 3895 bytes .../mbcsgroupprober.cpython-311.pyc | Bin 0 -> 1879 bytes .../__pycache__/mbcssm.cpython-311.pyc | Bin 0 -> 31271 bytes .../sbcharsetprober.cpython-311.pyc | Bin 0 -> 5601 bytes .../sbcsgroupprober.cpython-311.pyc | Bin 0 -> 2933 bytes .../__pycache__/sjisprober.cpython-311.pyc | Bin 0 -> 4500 bytes .../universaldetector.cpython-311.pyc | Bin 0 -> 11323 bytes .../__pycache__/utf1632prober.cpython-311.pyc | Bin 0 -> 10093 bytes .../__pycache__/utf8prober.cpython-311.pyc | Bin 0 -> 3241 bytes .../__pycache__/version.cpython-311.pyc | Bin 0 -> 519 bytes .../pip/_vendor/chardet/big5freq.py | 386 + .../pip/_vendor/chardet/big5prober.py | 47 + .../pip/_vendor/chardet/chardistribution.py | 259 + .../pip/_vendor/chardet/charsetgroupprober.py | 109 + .../pip/_vendor/chardet/charsetprober.py | 138 + .../pip/_vendor/chardet/cli/__init__.py | 0 .../cli/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 218 bytes .../__pycache__/chardetect.cpython-311.pyc | Bin 0 -> 3403 bytes .../pip/_vendor/chardet/cli/chardetect.py | 86 + .../pip/_vendor/chardet/codingstatemachine.py | 88 + .../pip/_vendor/chardet/cp949prober.py | 49 + .../pip/_vendor/chardet/enums.py | 82 + .../pip/_vendor/chardet/escprober.py | 102 + .../pip/_vendor/chardet/escsm.py | 260 + .../pip/_vendor/chardet/eucjpprober.py | 95 + .../pip/_vendor/chardet/euckrfreq.py | 196 + .../pip/_vendor/chardet/euckrprober.py | 47 + .../pip/_vendor/chardet/euctwfreq.py | 388 + .../pip/_vendor/chardet/euctwprober.py | 47 + .../pip/_vendor/chardet/gb2312freq.py | 284 + .../pip/_vendor/chardet/gb2312prober.py | 47 + .../pip/_vendor/chardet/hebrewprober.py | 302 + .../pip/_vendor/chardet/jisfreq.py | 325 + .../pip/_vendor/chardet/johabfreq.py | 2382 +++++ .../pip/_vendor/chardet/johabprober.py | 47 + .../pip/_vendor/chardet/jpcntx.py | 237 + .../pip/_vendor/chardet/langbulgarianmodel.py | 4649 +++++++++ .../pip/_vendor/chardet/langgreekmodel.py | 4397 +++++++++ .../pip/_vendor/chardet/langhebrewmodel.py | 4380 +++++++++ .../pip/_vendor/chardet/langhungarianmodel.py | 4649 +++++++++ .../pip/_vendor/chardet/langrussianmodel.py | 5725 +++++++++++ .../pip/_vendor/chardet/langthaimodel.py | 4380 +++++++++ .../pip/_vendor/chardet/langturkishmodel.py | 4380 +++++++++ .../pip/_vendor/chardet/latin1prober.py | 145 + .../pip/_vendor/chardet/mbcharsetprober.py | 95 + .../pip/_vendor/chardet/mbcsgroupprober.py | 56 + .../pip/_vendor/chardet/mbcssm.py | 660 ++ .../pip/_vendor/chardet/metadata/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 223 bytes .../__pycache__/languages.cpython-311.pyc | Bin 0 -> 10430 bytes .../pip/_vendor/chardet/metadata/languages.py | 351 + .../pip/_vendor/chardet/sbcharsetprober.py | 160 + .../pip/_vendor/chardet/sbcsgroupprober.py | 88 + .../pip/_vendor/chardet/sjisprober.py | 98 + .../pip/_vendor/chardet/universaldetector.py | 328 + .../pip/_vendor/chardet/utf1632prober.py | 223 + .../pip/_vendor/chardet/utf8prober.py | 80 + .../pip/_vendor/chardet/version.py | 9 + .../pip/_vendor/colorama/__init__.py | 6 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 549 bytes .../colorama/__pycache__/ansi.cpython-311.pyc | Bin 0 -> 4588 bytes .../__pycache__/ansitowin32.cpython-311.pyc | Bin 0 -> 15755 bytes .../__pycache__/initialise.cpython-311.pyc | Bin 0 -> 2910 bytes .../__pycache__/win32.cpython-311.pyc | Bin 0 -> 6929 bytes .../__pycache__/winterm.cpython-311.pyc | Bin 0 -> 8048 bytes .../pip/_vendor/colorama/ansi.py | 102 + .../pip/_vendor/colorama/ansitowin32.py | 266 + .../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-311.pyc | Bin 0 -> 1459 bytes .../__pycache__/compat.cpython-311.pyc | Bin 0 -> 52325 bytes .../__pycache__/database.cpython-311.pyc | Bin 0 -> 72113 bytes .../distlib/__pycache__/index.cpython-311.pyc | Bin 0 -> 26702 bytes .../__pycache__/locators.cpython-311.pyc | Bin 0 -> 65878 bytes .../__pycache__/manifest.cpython-311.pyc | Bin 0 -> 17045 bytes .../__pycache__/markers.cpython-311.pyc | Bin 0 -> 8181 bytes .../__pycache__/metadata.cpython-311.pyc | Bin 0 -> 47129 bytes .../__pycache__/resources.cpython-311.pyc | Bin 0 -> 19008 bytes .../__pycache__/scripts.cpython-311.pyc | Bin 0 -> 21284 bytes .../distlib/__pycache__/util.cpython-311.pyc | Bin 0 -> 97463 bytes .../__pycache__/version.cpython-311.pyc | Bin 0 -> 34590 bytes .../distlib/__pycache__/wheel.cpython-311.pyc | Bin 0 -> 60394 bytes .../pip/_vendor/distlib/compat.py | 1116 +++ .../pip/_vendor/distlib/database.py | 1350 +++ .../pip/_vendor/distlib/index.py | 508 + .../pip/_vendor/distlib/locators.py | 1300 +++ .../pip/_vendor/distlib/manifest.py | 393 + .../pip/_vendor/distlib/markers.py | 152 + .../pip/_vendor/distlib/metadata.py | 1076 +++ .../pip/_vendor/distlib/resources.py | 358 + .../pip/_vendor/distlib/scripts.py | 437 + .../site-packages/pip/_vendor/distlib/t32.exe | Bin 0 -> 97792 bytes .../pip/_vendor/distlib/t64-arm.exe | Bin 0 -> 182784 bytes .../site-packages/pip/_vendor/distlib/t64.exe | Bin 0 -> 108032 bytes .../site-packages/pip/_vendor/distlib/util.py | 1932 ++++ .../pip/_vendor/distlib/version.py | 739 ++ .../site-packages/pip/_vendor/distlib/w32.exe | Bin 0 -> 91648 bytes .../pip/_vendor/distlib/w64-arm.exe | Bin 0 -> 168448 bytes .../site-packages/pip/_vendor/distlib/w64.exe | Bin 0 -> 101888 bytes .../pip/_vendor/distlib/wheel.py | 1082 +++ .../pip/_vendor/distro/__init__.py | 54 + .../pip/_vendor/distro/__main__.py | 4 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 1212 bytes .../__pycache__/__main__.cpython-311.pyc | Bin 0 -> 346 bytes .../distro/__pycache__/distro.cpython-311.pyc | Bin 0 -> 56232 bytes .../pip/_vendor/distro/distro.py | 1374 +++ .../pip/_vendor/idna/__init__.py | 44 + .../idna/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 1113 bytes .../idna/__pycache__/codec.cpython-311.pyc | Bin 0 -> 5404 bytes .../idna/__pycache__/compat.cpython-311.pyc | Bin 0 -> 1030 bytes .../idna/__pycache__/core.cpython-311.pyc | Bin 0 -> 19465 bytes .../idna/__pycache__/idnadata.cpython-311.pyc | Bin 0 -> 38989 bytes .../__pycache__/intranges.cpython-311.pyc | Bin 0 -> 2998 bytes .../__pycache__/package_data.cpython-311.pyc | Bin 0 -> 233 bytes .../__pycache__/uts46data.cpython-311.pyc | Bin 0 -> 163213 bytes .../site-packages/pip/_vendor/idna/codec.py | 112 + .../site-packages/pip/_vendor/idna/compat.py | 13 + .../site-packages/pip/_vendor/idna/core.py | 400 + .../pip/_vendor/idna/idnadata.py | 2151 +++++ .../pip/_vendor/idna/intranges.py | 54 + .../pip/_vendor/idna/package_data.py | 2 + .../pip/_vendor/idna/uts46data.py | 8600 +++++++++++++++++ .../pip/_vendor/msgpack/__init__.py | 57 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 2092 bytes .../__pycache__/exceptions.cpython-311.pyc | Bin 0 -> 2393 bytes .../msgpack/__pycache__/ext.cpython-311.pyc | Bin 0 -> 9179 bytes .../__pycache__/fallback.cpython-311.pyc | Bin 0 -> 47206 bytes .../pip/_vendor/msgpack/exceptions.py | 48 + .../site-packages/pip/_vendor/msgpack/ext.py | 193 + .../pip/_vendor/msgpack/fallback.py | 1010 ++ .../pip/_vendor/packaging/__about__.py | 26 + .../pip/_vendor/packaging/__init__.py | 25 + .../__pycache__/__about__.cpython-311.pyc | Bin 0 -> 657 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 578 bytes .../__pycache__/_manylinux.cpython-311.pyc | Bin 0 -> 13244 bytes .../__pycache__/_musllinux.cpython-311.pyc | Bin 0 -> 8012 bytes .../__pycache__/_structures.cpython-311.pyc | Bin 0 -> 3700 bytes .../__pycache__/markers.cpython-311.pyc | Bin 0 -> 16540 bytes .../__pycache__/requirements.cpython-311.pyc | Bin 0 -> 7655 bytes .../__pycache__/specifiers.cpython-311.pyc | Bin 0 -> 34378 bytes .../__pycache__/tags.cpython-311.pyc | Bin 0 -> 21363 bytes .../__pycache__/utils.cpython-311.pyc | Bin 0 -> 6698 bytes .../__pycache__/version.cpython-311.pyc | Bin 0 -> 21890 bytes .../pip/_vendor/packaging/_manylinux.py | 301 + .../pip/_vendor/packaging/_musllinux.py | 136 + .../pip/_vendor/packaging/_structures.py | 61 + .../pip/_vendor/packaging/markers.py | 304 + .../pip/_vendor/packaging/requirements.py | 146 + .../pip/_vendor/packaging/specifiers.py | 802 ++ .../pip/_vendor/packaging/tags.py | 487 + .../pip/_vendor/packaging/utils.py | 136 + .../pip/_vendor/packaging/version.py | 504 + .../pip/_vendor/pep517/__init__.py | 6 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 357 bytes .../__pycache__/_compat.cpython-311.pyc | Bin 0 -> 410 bytes .../pep517/__pycache__/build.cpython-311.pyc | Bin 0 -> 6653 bytes .../pep517/__pycache__/check.cpython-311.pyc | Bin 0 -> 11815 bytes .../__pycache__/colorlog.cpython-311.pyc | Bin 0 -> 4860 bytes .../__pycache__/dirtools.cpython-311.pyc | Bin 0 -> 1338 bytes .../__pycache__/envbuild.cpython-311.pyc | Bin 0 -> 7497 bytes .../pep517/__pycache__/meta.cpython-311.pyc | Bin 0 -> 5764 bytes .../__pycache__/wrappers.cpython-311.pyc | Bin 0 -> 18312 bytes .../pip/_vendor/pep517/_compat.py | 8 + .../site-packages/pip/_vendor/pep517/build.py | 126 + .../site-packages/pip/_vendor/pep517/check.py | 207 + .../pip/_vendor/pep517/colorlog.py | 113 + .../pip/_vendor/pep517/dirtools.py | 19 + .../pip/_vendor/pep517/envbuild.py | 170 + .../pip/_vendor/pep517/in_process/__init__.py | 26 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 1804 bytes .../__pycache__/_in_process.cpython-311.pyc | Bin 0 -> 16493 bytes .../_vendor/pep517/in_process/_in_process.py | 351 + .../site-packages/pip/_vendor/pep517/meta.py | 93 + .../pip/_vendor/pep517/wrappers.py | 362 + .../pip/_vendor/pkg_resources/__init__.py | 3296 +++++++ .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 158246 bytes .../__pycache__/py31compat.cpython-311.pyc | Bin 0 -> 999 bytes .../pip/_vendor/pkg_resources/py31compat.py | 23 + .../pip/_vendor/platformdirs/__init__.py | 340 + .../pip/_vendor/platformdirs/__main__.py | 46 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 12804 bytes .../__pycache__/__main__.cpython-311.pyc | Bin 0 -> 2142 bytes .../__pycache__/android.cpython-311.pyc | Bin 0 -> 6372 bytes .../__pycache__/api.cpython-311.pyc | Bin 0 -> 7199 bytes .../__pycache__/macos.cpython-311.pyc | Bin 0 -> 4609 bytes .../__pycache__/unix.cpython-311.pyc | Bin 0 -> 11040 bytes .../__pycache__/version.cpython-311.pyc | Bin 0 -> 325 bytes .../__pycache__/windows.cpython-311.pyc | Bin 0 -> 9847 bytes .../pip/_vendor/platformdirs/android.py | 120 + .../pip/_vendor/platformdirs/api.py | 156 + .../pip/_vendor/platformdirs/macos.py | 64 + .../pip/_vendor/platformdirs/unix.py | 181 + .../pip/_vendor/platformdirs/version.py | 4 + .../pip/_vendor/platformdirs/windows.py | 182 + .../pip/_vendor/pygments/__init__.py | 82 + .../pip/_vendor/pygments/__main__.py | 17 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 3860 bytes .../__pycache__/__main__.cpython-311.pyc | Bin 0 -> 796 bytes .../__pycache__/cmdline.cpython-311.pyc | Bin 0 -> 30307 bytes .../__pycache__/console.cpython-311.pyc | Bin 0 -> 3059 bytes .../__pycache__/filter.cpython-311.pyc | Bin 0 -> 3520 bytes .../__pycache__/formatter.cpython-311.pyc | Bin 0 -> 3886 bytes .../__pycache__/lexer.cpython-311.pyc | Bin 0 -> 40414 bytes .../__pycache__/modeline.cpython-311.pyc | Bin 0 -> 1739 bytes .../__pycache__/plugin.cpython-311.pyc | Bin 0 -> 3752 bytes .../__pycache__/regexopt.cpython-311.pyc | Bin 0 -> 5046 bytes .../__pycache__/scanner.cpython-311.pyc | Bin 0 -> 4901 bytes .../__pycache__/sphinxext.cpython-311.pyc | Bin 0 -> 8332 bytes .../__pycache__/style.cpython-311.pyc | Bin 0 -> 7440 bytes .../__pycache__/token.cpython-311.pyc | Bin 0 -> 7480 bytes .../__pycache__/unistring.cpython-311.pyc | Bin 0 -> 33814 bytes .../pygments/__pycache__/util.cpython-311.pyc | Bin 0 -> 14607 bytes .../pip/_vendor/pygments/cmdline.py | 668 ++ .../pip/_vendor/pygments/console.py | 70 + .../pip/_vendor/pygments/filter.py | 71 + .../pip/_vendor/pygments/filters/__init__.py | 940 ++ .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 40120 bytes .../pip/_vendor/pygments/formatter.py | 94 + .../_vendor/pygments/formatters/__init__.py | 143 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 6886 bytes .../__pycache__/_mapping.cpython-311.pyc | Bin 0 -> 4168 bytes .../__pycache__/bbcode.cpython-311.pyc | Bin 0 -> 4494 bytes .../__pycache__/groff.cpython-311.pyc | Bin 0 -> 7827 bytes .../__pycache__/html.cpython-311.pyc | Bin 0 -> 42612 bytes .../__pycache__/img.cpython-311.pyc | Bin 0 -> 28584 bytes .../__pycache__/irc.cpython-311.pyc | Bin 0 -> 7687 bytes .../__pycache__/latex.cpython-311.pyc | Bin 0 -> 21820 bytes .../__pycache__/other.cpython-311.pyc | Bin 0 -> 7648 bytes .../__pycache__/pangomarkup.cpython-311.pyc | Bin 0 -> 3192 bytes .../__pycache__/rtf.cpython-311.pyc | Bin 0 -> 6859 bytes .../__pycache__/svg.cpython-311.pyc | Bin 0 -> 9679 bytes .../__pycache__/terminal.cpython-311.pyc | Bin 0 -> 6058 bytes .../__pycache__/terminal256.cpython-311.pyc | Bin 0 -> 16424 bytes .../_vendor/pygments/formatters/_mapping.py | 23 + .../pip/_vendor/pygments/formatters/bbcode.py | 108 + .../pip/_vendor/pygments/formatters/groff.py | 170 + .../pip/_vendor/pygments/formatters/html.py | 989 ++ .../pip/_vendor/pygments/formatters/img.py | 645 ++ .../pip/_vendor/pygments/formatters/irc.py | 179 + .../pip/_vendor/pygments/formatters/latex.py | 521 + .../pip/_vendor/pygments/formatters/other.py | 161 + .../pygments/formatters/pangomarkup.py | 83 + .../pip/_vendor/pygments/formatters/rtf.py | 146 + .../pip/_vendor/pygments/formatters/svg.py | 188 + .../_vendor/pygments/formatters/terminal.py | 127 + .../pygments/formatters/terminal256.py | 338 + .../pip/_vendor/pygments/lexer.py | 882 ++ .../pip/_vendor/pygments/lexers/__init__.py | 335 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 15163 bytes .../__pycache__/_mapping.cpython-311.pyc | Bin 0 -> 62794 bytes .../lexers/__pycache__/python.cpython-311.pyc | Bin 0 -> 43995 bytes .../pip/_vendor/pygments/lexers/_mapping.py | 541 ++ .../pip/_vendor/pygments/lexers/python.py | 1204 +++ .../pip/_vendor/pygments/modeline.py | 43 + .../pip/_vendor/pygments/plugin.py | 88 + .../pip/_vendor/pygments/regexopt.py | 91 + .../pip/_vendor/pygments/scanner.py | 104 + .../pip/_vendor/pygments/sphinxext.py | 155 + .../pip/_vendor/pygments/style.py | 197 + .../pip/_vendor/pygments/styles/__init__.py | 97 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 4473 bytes .../pip/_vendor/pygments/token.py | 213 + .../pip/_vendor/pygments/unistring.py | 153 + .../pip/_vendor/pygments/util.py | 308 + .../pip/_vendor/pyparsing/__init__.py | 331 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 8363 bytes .../__pycache__/actions.cpython-311.pyc | Bin 0 -> 8477 bytes .../__pycache__/common.cpython-311.pyc | Bin 0 -> 14799 bytes .../__pycache__/core.cpython-311.pyc | Bin 0 -> 277685 bytes .../__pycache__/exceptions.cpython-311.pyc | Bin 0 -> 12941 bytes .../__pycache__/helpers.cpython-311.pyc | Bin 0 -> 53642 bytes .../__pycache__/results.cpython-311.pyc | Bin 0 -> 36325 bytes .../__pycache__/testing.cpython-311.pyc | Bin 0 -> 19521 bytes .../__pycache__/unicode.cpython-311.pyc | Bin 0 -> 15379 bytes .../__pycache__/util.cpython-311.pyc | Bin 0 -> 14278 bytes .../pip/_vendor/pyparsing/actions.py | 207 + .../pip/_vendor/pyparsing/common.py | 424 + .../pip/_vendor/pyparsing/core.py | 5814 +++++++++++ .../pip/_vendor/pyparsing/diagram/__init__.py | 642 ++ .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 28044 bytes .../pip/_vendor/pyparsing/exceptions.py | 267 + .../pip/_vendor/pyparsing/helpers.py | 1088 +++ .../pip/_vendor/pyparsing/results.py | 760 ++ .../pip/_vendor/pyparsing/testing.py | 331 + .../pip/_vendor/pyparsing/unicode.py | 352 + .../pip/_vendor/pyparsing/util.py | 235 + .../pip/_vendor/requests/__init__.py | 182 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 6465 bytes .../__pycache__/__version__.cpython-311.pyc | Bin 0 -> 607 bytes .../_internal_utils.cpython-311.pyc | Bin 0 -> 2099 bytes .../__pycache__/adapters.cpython-311.pyc | Bin 0 -> 24902 bytes .../requests/__pycache__/api.cpython-311.pyc | Bin 0 -> 7447 bytes .../requests/__pycache__/auth.cpython-311.pyc | Bin 0 -> 14646 bytes .../__pycache__/certs.cpython-311.pyc | Bin 0 -> 998 bytes .../__pycache__/compat.cpython-311.pyc | Bin 0 -> 1824 bytes .../__pycache__/cookies.cpython-311.pyc | Bin 0 -> 27126 bytes .../__pycache__/exceptions.cpython-311.pyc | Bin 0 -> 8541 bytes .../requests/__pycache__/help.cpython-311.pyc | Bin 0 -> 4536 bytes .../__pycache__/hooks.cpython-311.pyc | Bin 0 -> 1266 bytes .../__pycache__/models.cpython-311.pyc | Bin 0 -> 38796 bytes .../__pycache__/packages.cpython-311.pyc | Bin 0 -> 846 bytes .../__pycache__/sessions.cpython-311.pyc | Bin 0 -> 29635 bytes .../__pycache__/status_codes.cpython-311.pyc | Bin 0 -> 6253 bytes .../__pycache__/structures.cpython-311.pyc | Bin 0 -> 6238 bytes .../__pycache__/utils.cpython-311.pyc | Bin 0 -> 40152 bytes .../pip/_vendor/requests/__version__.py | 14 + .../pip/_vendor/requests/_internal_utils.py | 48 + .../pip/_vendor/requests/adapters.py | 584 ++ .../site-packages/pip/_vendor/requests/api.py | 157 + .../pip/_vendor/requests/auth.py | 315 + .../pip/_vendor/requests/certs.py | 24 + .../pip/_vendor/requests/compat.py | 67 + .../pip/_vendor/requests/cookies.py | 561 ++ .../pip/_vendor/requests/exceptions.py | 141 + .../pip/_vendor/requests/help.py | 131 + .../pip/_vendor/requests/hooks.py | 33 + .../pip/_vendor/requests/models.py | 1034 ++ .../pip/_vendor/requests/packages.py | 16 + .../pip/_vendor/requests/sessions.py | 831 ++ .../pip/_vendor/requests/status_codes.py | 128 + .../pip/_vendor/requests/structures.py | 99 + .../pip/_vendor/requests/utils.py | 1086 +++ .../pip/_vendor/resolvelib/__init__.py | 26 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 769 bytes .../__pycache__/providers.cpython-311.pyc | Bin 0 -> 7088 bytes .../__pycache__/reporters.cpython-311.pyc | Bin 0 -> 2818 bytes .../__pycache__/resolvers.cpython-311.pyc | Bin 0 -> 25264 bytes .../__pycache__/structs.cpython-311.pyc | Bin 0 -> 11346 bytes .../pip/_vendor/resolvelib/compat/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 224 bytes .../collections_abc.cpython-311.pyc | Bin 0 -> 499 bytes .../resolvelib/compat/collections_abc.py | 6 + .../pip/_vendor/resolvelib/providers.py | 133 + .../pip/_vendor/resolvelib/reporters.py | 43 + .../pip/_vendor/resolvelib/resolvers.py | 482 + .../pip/_vendor/resolvelib/structs.py | 165 + .../pip/_vendor/rich/__init__.py | 176 + .../pip/_vendor/rich/__main__.py | 282 + .../rich/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 7373 bytes .../rich/__pycache__/__main__.cpython-311.pyc | Bin 0 -> 11761 bytes .../__pycache__/_cell_widths.cpython-311.pyc | Bin 0 -> 7851 bytes .../__pycache__/_emoji_codes.cpython-311.pyc | Bin 0 -> 208538 bytes .../_emoji_replace.cpython-311.pyc | Bin 0 -> 1950 bytes .../_export_format.cpython-311.pyc | Bin 0 -> 2355 bytes .../__pycache__/_extension.cpython-311.pyc | Bin 0 -> 651 bytes .../rich/__pycache__/_inspect.cpython-311.pyc | Bin 0 -> 14203 bytes .../__pycache__/_log_render.cpython-311.pyc | Bin 0 -> 4785 bytes .../rich/__pycache__/_loop.cpython-311.pyc | Bin 0 -> 2131 bytes .../__pycache__/_palettes.cpython-311.pyc | Bin 0 -> 5267 bytes .../rich/__pycache__/_pick.cpython-311.pyc | Bin 0 -> 812 bytes .../rich/__pycache__/_ratio.cpython-311.pyc | Bin 0 -> 7950 bytes .../__pycache__/_spinners.cpython-311.pyc | Bin 0 -> 13700 bytes .../rich/__pycache__/_stack.cpython-311.pyc | Bin 0 -> 1146 bytes .../rich/__pycache__/_timer.cpython-311.pyc | Bin 0 -> 999 bytes .../_win32_console.cpython-311.pyc | Bin 0 -> 30187 bytes .../rich/__pycache__/_windows.cpython-311.pyc | Bin 0 -> 2846 bytes .../_windows_renderer.cpython-311.pyc | Bin 0 -> 4037 bytes .../rich/__pycache__/_wrap.cpython-311.pyc | Bin 0 -> 2802 bytes .../rich/__pycache__/abc.cpython-311.pyc | Bin 0 -> 1943 bytes .../rich/__pycache__/align.cpython-311.pyc | Bin 0 -> 13492 bytes .../rich/__pycache__/ansi.cpython-311.pyc | Bin 0 -> 10469 bytes .../rich/__pycache__/bar.cpython-311.pyc | Bin 0 -> 4565 bytes .../rich/__pycache__/box.cpython-311.pyc | Bin 0 -> 13007 bytes .../rich/__pycache__/cells.cpython-311.pyc | Bin 0 -> 6457 bytes .../rich/__pycache__/color.cpython-311.pyc | Bin 0 -> 27399 bytes .../__pycache__/color_triplet.cpython-311.pyc | Bin 0 -> 1891 bytes .../rich/__pycache__/columns.cpython-311.pyc | Bin 0 -> 10662 bytes .../rich/__pycache__/console.cpython-311.pyc | Bin 0 -> 121281 bytes .../__pycache__/constrain.cpython-311.pyc | Bin 0 -> 2483 bytes .../__pycache__/containers.cpython-311.pyc | Bin 0 -> 10824 bytes .../rich/__pycache__/control.cpython-311.pyc | Bin 0 -> 11915 bytes .../default_styles.cpython-311.pyc | Bin 0 -> 12515 bytes .../rich/__pycache__/diagnose.cpython-311.pyc | Bin 0 -> 1838 bytes .../rich/__pycache__/emoji.cpython-311.pyc | Bin 0 -> 4816 bytes .../rich/__pycache__/errors.cpython-311.pyc | Bin 0 -> 2347 bytes .../__pycache__/file_proxy.cpython-311.pyc | Bin 0 -> 3795 bytes .../rich/__pycache__/filesize.cpython-311.pyc | Bin 0 -> 3318 bytes .../__pycache__/highlighter.cpython-311.pyc | Bin 0 -> 11006 bytes .../rich/__pycache__/json.cpython-311.pyc | Bin 0 -> 6699 bytes .../rich/__pycache__/jupyter.cpython-311.pyc | Bin 0 -> 6422 bytes .../rich/__pycache__/layout.cpython-311.pyc | Bin 0 -> 23401 bytes .../rich/__pycache__/live.cpython-311.pyc | Bin 0 -> 21150 bytes .../__pycache__/live_render.cpython-311.pyc | Bin 0 -> 5163 bytes .../rich/__pycache__/logging.cpython-311.pyc | Bin 0 -> 14252 bytes .../rich/__pycache__/markup.cpython-311.pyc | Bin 0 -> 10456 bytes .../rich/__pycache__/measure.cpython-311.pyc | Bin 0 -> 7289 bytes .../rich/__pycache__/padding.cpython-311.pyc | Bin 0 -> 7505 bytes .../rich/__pycache__/pager.cpython-311.pyc | Bin 0 -> 2263 bytes .../rich/__pycache__/palette.cpython-311.pyc | Bin 0 -> 5996 bytes .../rich/__pycache__/panel.cpython-311.pyc | Bin 0 -> 11177 bytes .../rich/__pycache__/pretty.cpython-311.pyc | Bin 0 -> 43855 bytes .../rich/__pycache__/progress.cpython-311.pyc | Bin 0 -> 82518 bytes .../__pycache__/progress_bar.cpython-311.pyc | Bin 0 -> 11026 bytes .../rich/__pycache__/prompt.cpython-311.pyc | Bin 0 -> 16396 bytes .../rich/__pycache__/protocol.cpython-311.pyc | Bin 0 -> 2114 bytes .../rich/__pycache__/region.cpython-311.pyc | Bin 0 -> 677 bytes .../rich/__pycache__/repr.cpython-311.pyc | Bin 0 -> 7698 bytes .../rich/__pycache__/rule.cpython-311.pyc | Bin 0 -> 7715 bytes .../rich/__pycache__/scope.cpython-311.pyc | Bin 0 -> 4368 bytes .../rich/__pycache__/screen.cpython-311.pyc | Bin 0 -> 2792 bytes .../rich/__pycache__/segment.cpython-311.pyc | Bin 0 -> 31559 bytes .../rich/__pycache__/spinner.cpython-311.pyc | Bin 0 -> 6908 bytes .../rich/__pycache__/status.cpython-311.pyc | Bin 0 -> 6776 bytes .../rich/__pycache__/style.cpython-311.pyc | Bin 0 -> 34157 bytes .../rich/__pycache__/styled.cpython-311.pyc | Bin 0 -> 2457 bytes .../rich/__pycache__/syntax.cpython-311.pyc | Bin 0 -> 41985 bytes .../rich/__pycache__/table.cpython-311.pyc | Bin 0 -> 48512 bytes .../terminal_theme.cpython-311.pyc | Bin 0 -> 3723 bytes .../rich/__pycache__/text.cpython-311.pyc | Bin 0 -> 64109 bytes .../rich/__pycache__/theme.cpython-311.pyc | Bin 0 -> 7161 bytes .../rich/__pycache__/themes.cpython-311.pyc | Bin 0 -> 373 bytes .../__pycache__/traceback.cpython-311.pyc | Bin 0 -> 31740 bytes .../rich/__pycache__/tree.cpython-311.pyc | Bin 0 -> 12544 bytes .../pip/_vendor/rich/_cell_widths.py | 451 + .../pip/_vendor/rich/_emoji_codes.py | 3610 +++++++ .../pip/_vendor/rich/_emoji_replace.py | 32 + .../pip/_vendor/rich/_export_format.py | 78 + .../pip/_vendor/rich/_extension.py | 10 + .../pip/_vendor/rich/_inspect.py | 270 + .../pip/_vendor/rich/_log_render.py | 94 + .../site-packages/pip/_vendor/rich/_loop.py | 43 + .../pip/_vendor/rich/_palettes.py | 309 + .../site-packages/pip/_vendor/rich/_pick.py | 17 + .../site-packages/pip/_vendor/rich/_ratio.py | 160 + .../pip/_vendor/rich/_spinners.py | 482 + .../site-packages/pip/_vendor/rich/_stack.py | 16 + .../site-packages/pip/_vendor/rich/_timer.py | 19 + .../pip/_vendor/rich/_win32_console.py | 662 ++ .../pip/_vendor/rich/_windows.py | 72 + .../pip/_vendor/rich/_windows_renderer.py | 56 + .../site-packages/pip/_vendor/rich/_wrap.py | 56 + .../Lib/site-packages/pip/_vendor/rich/abc.py | 33 + .../site-packages/pip/_vendor/rich/align.py | 311 + .../site-packages/pip/_vendor/rich/ansi.py | 237 + .../Lib/site-packages/pip/_vendor/rich/bar.py | 94 + .../Lib/site-packages/pip/_vendor/rich/box.py | 517 + .../site-packages/pip/_vendor/rich/cells.py | 154 + .../site-packages/pip/_vendor/rich/color.py | 615 ++ .../pip/_vendor/rich/color_triplet.py | 38 + .../site-packages/pip/_vendor/rich/columns.py | 187 + .../site-packages/pip/_vendor/rich/console.py | 2572 +++++ .../pip/_vendor/rich/constrain.py | 37 + .../pip/_vendor/rich/containers.py | 167 + .../site-packages/pip/_vendor/rich/control.py | 225 + .../pip/_vendor/rich/default_styles.py | 188 + .../pip/_vendor/rich/diagnose.py | 37 + .../site-packages/pip/_vendor/rich/emoji.py | 96 + .../site-packages/pip/_vendor/rich/errors.py | 34 + .../pip/_vendor/rich/file_proxy.py | 54 + .../pip/_vendor/rich/filesize.py | 89 + .../pip/_vendor/rich/highlighter.py | 232 + .../site-packages/pip/_vendor/rich/json.py | 140 + .../site-packages/pip/_vendor/rich/jupyter.py | 101 + .../site-packages/pip/_vendor/rich/layout.py | 445 + .../site-packages/pip/_vendor/rich/live.py | 373 + .../pip/_vendor/rich/live_render.py | 113 + .../site-packages/pip/_vendor/rich/logging.py | 280 + .../site-packages/pip/_vendor/rich/markup.py | 246 + .../site-packages/pip/_vendor/rich/measure.py | 151 + .../site-packages/pip/_vendor/rich/padding.py | 141 + .../site-packages/pip/_vendor/rich/pager.py | 34 + .../site-packages/pip/_vendor/rich/palette.py | 100 + .../site-packages/pip/_vendor/rich/panel.py | 251 + .../site-packages/pip/_vendor/rich/pretty.py | 1010 ++ .../pip/_vendor/rich/progress.py | 1703 ++++ .../pip/_vendor/rich/progress_bar.py | 224 + .../site-packages/pip/_vendor/rich/prompt.py | 376 + .../pip/_vendor/rich/protocol.py | 42 + .../site-packages/pip/_vendor/rich/region.py | 10 + .../site-packages/pip/_vendor/rich/repr.py | 152 + .../site-packages/pip/_vendor/rich/rule.py | 134 + .../site-packages/pip/_vendor/rich/scope.py | 86 + .../site-packages/pip/_vendor/rich/screen.py | 54 + .../site-packages/pip/_vendor/rich/segment.py | 739 ++ .../site-packages/pip/_vendor/rich/spinner.py | 136 + .../site-packages/pip/_vendor/rich/status.py | 132 + .../site-packages/pip/_vendor/rich/style.py | 771 ++ .../site-packages/pip/_vendor/rich/styled.py | 42 + .../site-packages/pip/_vendor/rich/syntax.py | 934 ++ .../site-packages/pip/_vendor/rich/table.py | 996 ++ .../pip/_vendor/rich/terminal_theme.py | 153 + .../site-packages/pip/_vendor/rich/text.py | 1286 +++ .../site-packages/pip/_vendor/rich/theme.py | 112 + .../site-packages/pip/_vendor/rich/themes.py | 5 + .../pip/_vendor/rich/traceback.py | 679 ++ .../site-packages/pip/_vendor/rich/tree.py | 251 + .venv/Lib/site-packages/pip/_vendor/six.py | 998 ++ .../pip/_vendor/tenacity/__init__.py | 519 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 27811 bytes .../__pycache__/_asyncio.cpython-311.pyc | Bin 0 -> 4818 bytes .../__pycache__/_utils.cpython-311.pyc | Bin 0 -> 2083 bytes .../__pycache__/after.cpython-311.pyc | Bin 0 -> 1710 bytes .../__pycache__/before.cpython-311.pyc | Bin 0 -> 1544 bytes .../__pycache__/before_sleep.cpython-311.pyc | Bin 0 -> 2121 bytes .../tenacity/__pycache__/nap.cpython-311.pyc | Bin 0 -> 1583 bytes .../__pycache__/retry.cpython-311.pyc | Bin 0 -> 15057 bytes .../tenacity/__pycache__/stop.cpython-311.pyc | Bin 0 -> 5911 bytes .../__pycache__/tornadoweb.cpython-311.pyc | Bin 0 -> 2929 bytes .../tenacity/__pycache__/wait.cpython-311.pyc | Bin 0 -> 13383 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 | 240 + .../pip/_vendor/tenacity/stop.py | 96 + .../pip/_vendor/tenacity/tornadoweb.py | 59 + .../pip/_vendor/tenacity/wait.py | 232 + .../pip/_vendor/tomli/__init__.py | 11 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 428 bytes .../tomli/__pycache__/_parser.cpython-311.pyc | Bin 0 -> 30867 bytes .../tomli/__pycache__/_re.cpython-311.pyc | Bin 0 -> 4507 bytes .../tomli/__pycache__/_types.cpython-311.pyc | Bin 0 -> 420 bytes .../pip/_vendor/tomli/_parser.py | 691 ++ .../site-packages/pip/_vendor/tomli/_re.py | 107 + .../site-packages/pip/_vendor/tomli/_types.py | 10 + .../pip/_vendor/typing_extensions.py | 2209 +++++ .../pip/_vendor/urllib3/__init__.py | 102 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 3726 bytes .../__pycache__/_collections.cpython-311.pyc | Bin 0 -> 18314 bytes .../__pycache__/_version.cpython-311.pyc | Bin 0 -> 236 bytes .../__pycache__/connection.cpython-311.pyc | Bin 0 -> 21910 bytes .../connectionpool.cpython-311.pyc | Bin 0 -> 37651 bytes .../__pycache__/exceptions.cpython-311.pyc | Bin 0 -> 16140 bytes .../__pycache__/fields.cpython-311.pyc | Bin 0 -> 11433 bytes .../__pycache__/filepost.cpython-311.pyc | Bin 0 -> 4514 bytes .../__pycache__/poolmanager.cpython-311.pyc | Bin 0 -> 21837 bytes .../__pycache__/request.cpython-311.pyc | Bin 0 -> 6677 bytes .../__pycache__/response.cpython-311.pyc | Bin 0 -> 35992 bytes .../pip/_vendor/urllib3/_collections.py | 337 + .../pip/_vendor/urllib3/_version.py | 2 + .../pip/_vendor/urllib3/connection.py | 567 ++ .../pip/_vendor/urllib3/connectionpool.py | 1110 +++ .../pip/_vendor/urllib3/contrib/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 222 bytes .../_appengine_environ.cpython-311.pyc | Bin 0 -> 1961 bytes .../__pycache__/appengine.cpython-311.pyc | Bin 0 -> 12156 bytes .../__pycache__/ntlmpool.cpython-311.pyc | Bin 0 -> 6320 bytes .../__pycache__/pyopenssl.cpython-311.pyc | Bin 0 -> 25658 bytes .../securetransport.cpython-311.pyc | Bin 0 -> 36861 bytes .../contrib/__pycache__/socks.cpython-311.pyc | Bin 0 -> 8106 bytes .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 239 bytes .../__pycache__/bindings.cpython-311.pyc | Bin 0 -> 16986 bytes .../__pycache__/low_level.cpython-311.pyc | Bin 0 -> 15623 bytes .../contrib/_securetransport/bindings.py | 519 + .../contrib/_securetransport/low_level.py | 397 + .../pip/_vendor/urllib3/contrib/appengine.py | 314 + .../pip/_vendor/urllib3/contrib/ntlmpool.py | 130 + .../pip/_vendor/urllib3/contrib/pyopenssl.py | 519 + .../urllib3/contrib/securetransport.py | 921 ++ .../pip/_vendor/urllib3/contrib/socks.py | 216 + .../pip/_vendor/urllib3/exceptions.py | 323 + .../pip/_vendor/urllib3/fields.py | 274 + .../pip/_vendor/urllib3/filepost.py | 98 + .../pip/_vendor/urllib3/packages/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 223 bytes .../packages/__pycache__/six.cpython-311.pyc | Bin 0 -> 46465 bytes .../urllib3/packages/backports/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 233 bytes .../__pycache__/makefile.cpython-311.pyc | Bin 0 -> 1980 bytes .../urllib3/packages/backports/makefile.py | 51 + .../pip/_vendor/urllib3/packages/six.py | 1076 +++ .../pip/_vendor/urllib3/poolmanager.py | 537 + .../pip/_vendor/urllib3/request.py | 170 + .../pip/_vendor/urllib3/response.py | 866 ++ .../pip/_vendor/urllib3/util/__init__.py | 49 + .../util/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 1425 bytes .../__pycache__/connection.cpython-311.pyc | Bin 0 -> 5152 bytes .../util/__pycache__/proxy.cpython-311.pyc | Bin 0 -> 1734 bytes .../util/__pycache__/queue.cpython-311.pyc | Bin 0 -> 1517 bytes .../util/__pycache__/request.cpython-311.pyc | Bin 0 -> 4637 bytes .../util/__pycache__/response.cpython-311.pyc | Bin 0 -> 3506 bytes .../util/__pycache__/retry.cpython-311.pyc | Bin 0 -> 22758 bytes .../util/__pycache__/ssl_.cpython-311.pyc | Bin 0 -> 16837 bytes .../ssl_match_hostname.cpython-311.pyc | Bin 0 -> 5816 bytes .../__pycache__/ssltransport.cpython-311.pyc | Bin 0 -> 11645 bytes .../util/__pycache__/timeout.cpython-311.pyc | Bin 0 -> 11053 bytes .../util/__pycache__/url.cpython-311.pyc | Bin 0 -> 17566 bytes .../util/__pycache__/wait.cpython-311.pyc | Bin 0 -> 5019 bytes .../pip/_vendor/urllib3/util/connection.py | 149 + .../pip/_vendor/urllib3/util/proxy.py | 57 + .../pip/_vendor/urllib3/util/queue.py | 22 + .../pip/_vendor/urllib3/util/request.py | 137 + .../pip/_vendor/urllib3/util/response.py | 107 + .../pip/_vendor/urllib3/util/retry.py | 620 ++ .../pip/_vendor/urllib3/util/ssl_.py | 495 + .../urllib3/util/ssl_match_hostname.py | 159 + .../pip/_vendor/urllib3/util/ssltransport.py | 221 + .../pip/_vendor/urllib3/util/timeout.py | 268 + .../pip/_vendor/urllib3/util/url.py | 435 + .../pip/_vendor/urllib3/util/wait.py | 152 + .../Lib/site-packages/pip/_vendor/vendor.txt | 23 + .../pip/_vendor/webencodings/__init__.py | 342 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 12899 bytes .../__pycache__/labels.cpython-311.pyc | Bin 0 -> 7299 bytes .../__pycache__/mklabels.cpython-311.pyc | Bin 0 -> 3227 bytes .../__pycache__/tests.cpython-311.pyc | Bin 0 -> 11205 bytes .../x_user_defined.cpython-311.pyc | Bin 0 -> 3579 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 + .venv/Lib/site-packages/pip/py.typed | 4 + .../site-packages/pkg_resources/__init__.py | 3296 +++++++ .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 159588 bytes .../pkg_resources/_vendor/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 216 bytes .../__pycache__/appdirs.cpython-311.pyc | Bin 0 -> 29464 bytes .../_vendor/__pycache__/zipp.cpython-311.pyc | Bin 0 -> 16009 bytes .../pkg_resources/_vendor/appdirs.py | 608 ++ .../_vendor/importlib_resources/__init__.py | 36 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 850 bytes .../__pycache__/_adapters.cpython-311.pyc | Bin 0 -> 10767 bytes .../__pycache__/_common.cpython-311.pyc | Bin 0 -> 4294 bytes .../__pycache__/_compat.cpython-311.pyc | Bin 0 -> 5579 bytes .../__pycache__/_itertools.cpython-311.pyc | Bin 0 -> 1412 bytes .../__pycache__/_legacy.cpython-311.pyc | Bin 0 -> 6510 bytes .../__pycache__/abc.cpython-311.pyc | Bin 0 -> 7511 bytes .../__pycache__/readers.cpython-311.pyc | Bin 0 -> 8385 bytes .../__pycache__/simple.cpython-311.pyc | Bin 0 -> 6407 bytes .../_vendor/importlib_resources/_adapters.py | 170 + .../_vendor/importlib_resources/_common.py | 104 + .../_vendor/importlib_resources/_compat.py | 98 + .../_vendor/importlib_resources/_itertools.py | 35 + .../_vendor/importlib_resources/_legacy.py | 121 + .../_vendor/importlib_resources/abc.py | 137 + .../_vendor/importlib_resources/readers.py | 122 + .../_vendor/importlib_resources/simple.py | 116 + .../pkg_resources/_vendor/jaraco/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 223 bytes .../__pycache__/context.cpython-311.pyc | Bin 0 -> 9446 bytes .../__pycache__/functools.cpython-311.pyc | Bin 0 -> 20309 bytes .../pkg_resources/_vendor/jaraco/context.py | 213 + .../pkg_resources/_vendor/jaraco/functools.py | 525 + .../_vendor/jaraco/text/__init__.py | 599 ++ .../text/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 26626 bytes .../_vendor/more_itertools/__init__.py | 4 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 317 bytes .../__pycache__/more.cpython-311.pyc | Bin 0 -> 167978 bytes .../__pycache__/recipes.cpython-311.pyc | Bin 0 -> 26969 bytes .../_vendor/more_itertools/more.py | 4316 +++++++++ .../_vendor/more_itertools/recipes.py | 698 ++ .../_vendor/packaging/__about__.py | 26 + .../_vendor/packaging/__init__.py | 25 + .../__pycache__/__about__.cpython-311.pyc | Bin 0 -> 667 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 588 bytes .../__pycache__/_manylinux.cpython-311.pyc | Bin 0 -> 13254 bytes .../__pycache__/_musllinux.cpython-311.pyc | Bin 0 -> 8022 bytes .../__pycache__/_structures.cpython-311.pyc | Bin 0 -> 3710 bytes .../__pycache__/markers.cpython-311.pyc | Bin 0 -> 16559 bytes .../__pycache__/requirements.cpython-311.pyc | Bin 0 -> 7674 bytes .../__pycache__/specifiers.cpython-311.pyc | Bin 0 -> 34388 bytes .../__pycache__/tags.cpython-311.pyc | Bin 0 -> 21373 bytes .../__pycache__/utils.cpython-311.pyc | Bin 0 -> 6708 bytes .../__pycache__/version.cpython-311.pyc | Bin 0 -> 21900 bytes .../_vendor/packaging/_manylinux.py | 301 + .../_vendor/packaging/_musllinux.py | 136 + .../_vendor/packaging/_structures.py | 61 + .../_vendor/packaging/markers.py | 304 + .../_vendor/packaging/requirements.py | 146 + .../_vendor/packaging/specifiers.py | 802 ++ .../pkg_resources/_vendor/packaging/tags.py | 487 + .../pkg_resources/_vendor/packaging/utils.py | 136 + .../_vendor/packaging/version.py | 504 + .../_vendor/pyparsing/__init__.py | 331 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 8361 bytes .../__pycache__/actions.cpython-311.pyc | Bin 0 -> 8487 bytes .../__pycache__/common.cpython-311.pyc | Bin 0 -> 14809 bytes .../__pycache__/core.cpython-311.pyc | Bin 0 -> 277661 bytes .../__pycache__/exceptions.cpython-311.pyc | Bin 0 -> 12951 bytes .../__pycache__/helpers.cpython-311.pyc | Bin 0 -> 53652 bytes .../__pycache__/results.cpython-311.pyc | Bin 0 -> 36335 bytes .../__pycache__/testing.cpython-311.pyc | Bin 0 -> 19531 bytes .../__pycache__/unicode.cpython-311.pyc | Bin 0 -> 15389 bytes .../__pycache__/util.cpython-311.pyc | Bin 0 -> 14288 bytes .../_vendor/pyparsing/actions.py | 207 + .../pkg_resources/_vendor/pyparsing/common.py | 424 + .../pkg_resources/_vendor/pyparsing/core.py | 5814 +++++++++++ .../_vendor/pyparsing/diagram/__init__.py | 642 ++ .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 28024 bytes .../_vendor/pyparsing/exceptions.py | 267 + .../_vendor/pyparsing/helpers.py | 1088 +++ .../_vendor/pyparsing/results.py | 760 ++ .../_vendor/pyparsing/testing.py | 331 + .../_vendor/pyparsing/unicode.py | 352 + .../pkg_resources/_vendor/pyparsing/util.py | 235 + .../pkg_resources/_vendor/zipp.py | 329 + .../pkg_resources/extern/__init__.py | 76 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 4335 bytes .../setuptools-65.5.0.dist-info/INSTALLER | 1 + .../setuptools-65.5.0.dist-info/LICENSE | 19 + .../setuptools-65.5.0.dist-info/METADATA | 144 + .../setuptools-65.5.0.dist-info/RECORD | 466 + .../setuptools-65.5.0.dist-info/REQUESTED | 0 .../setuptools-65.5.0.dist-info/WHEEL | 5 + .../entry_points.txt | 57 + .../setuptools-65.5.0.dist-info/top_level.txt | 3 + .../Lib/site-packages/setuptools/__init__.py | 247 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 12925 bytes .../_deprecation_warning.cpython-311.pyc | Bin 0 -> 660 bytes .../__pycache__/_entry_points.cpython-311.pyc | Bin 0 -> 4809 bytes .../__pycache__/_imp.cpython-311.pyc | Bin 0 -> 3673 bytes .../__pycache__/_importlib.cpython-311.pyc | Bin 0 -> 1973 bytes .../__pycache__/_itertools.cpython-311.pyc | Bin 0 -> 1172 bytes .../__pycache__/_path.cpython-311.pyc | Bin 0 -> 1493 bytes .../__pycache__/_reqs.cpython-311.pyc | Bin 0 -> 1154 bytes .../__pycache__/archive_util.cpython-311.pyc | Bin 0 -> 10182 bytes .../__pycache__/build_meta.cpython-311.pyc | Bin 0 -> 28115 bytes .../__pycache__/dep_util.cpython-311.pyc | Bin 0 -> 1308 bytes .../__pycache__/depends.cpython-311.pyc | Bin 0 -> 7993 bytes .../__pycache__/discovery.cpython-311.pyc | Bin 0 -> 31137 bytes .../__pycache__/dist.cpython-311.pyc | Bin 0 -> 64075 bytes .../__pycache__/errors.cpython-311.pyc | Bin 0 -> 2969 bytes .../__pycache__/extension.cpython-311.pyc | Bin 0 -> 6825 bytes .../__pycache__/glob.cpython-311.pyc | Bin 0 -> 6582 bytes .../__pycache__/installer.cpython-311.pyc | Bin 0 -> 5632 bytes .../__pycache__/launch.cpython-311.pyc | Bin 0 -> 1548 bytes .../__pycache__/logging.cpython-311.pyc | Bin 0 -> 2066 bytes .../__pycache__/monkey.cpython-311.pyc | Bin 0 -> 7025 bytes .../__pycache__/msvc.cpython-311.pyc | Bin 0 -> 64198 bytes .../__pycache__/namespaces.cpython-311.pyc | Bin 0 -> 5680 bytes .../__pycache__/package_index.cpython-311.pyc | Bin 0 -> 60775 bytes .../__pycache__/py34compat.cpython-311.pyc | Bin 0 -> 735 bytes .../__pycache__/sandbox.cpython-311.pyc | Bin 0 -> 27351 bytes .../__pycache__/unicode_utils.cpython-311.pyc | Bin 0 -> 1837 bytes .../__pycache__/version.cpython-311.pyc | Bin 0 -> 455 bytes .../__pycache__/wheel.cpython-311.pyc | Bin 0 -> 15511 bytes .../windows_support.cpython-311.pyc | Bin 0 -> 1452 bytes .../setuptools/_deprecation_warning.py | 7 + .../setuptools/_distutils/__init__.py | 24 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 790 bytes .../__pycache__/_collections.cpython-311.pyc | Bin 0 -> 2940 bytes .../__pycache__/_functools.cpython-311.pyc | Bin 0 -> 881 bytes .../__pycache__/_macos_compat.cpython-311.pyc | Bin 0 -> 590 bytes .../__pycache__/_msvccompiler.cpython-311.pyc | Bin 0 -> 25125 bytes .../__pycache__/archive_util.cpython-311.pyc | Bin 0 -> 10677 bytes .../__pycache__/bcppcompiler.cpython-311.pyc | Bin 0 -> 13503 bytes .../__pycache__/ccompiler.cpython-311.pyc | Bin 0 -> 46402 bytes .../__pycache__/cmd.cpython-311.pyc | Bin 0 -> 18916 bytes .../__pycache__/config.cpython-311.pyc | Bin 0 -> 6065 bytes .../__pycache__/core.cpython-311.pyc | Bin 0 -> 10009 bytes .../cygwinccompiler.cpython-311.pyc | Bin 0 -> 13633 bytes .../__pycache__/debug.cpython-311.pyc | Bin 0 -> 342 bytes .../__pycache__/dep_util.cpython-311.pyc | Bin 0 -> 4009 bytes .../__pycache__/dir_util.cpython-311.pyc | Bin 0 -> 10384 bytes .../__pycache__/dist.cpython-311.pyc | Bin 0 -> 55431 bytes .../__pycache__/errors.cpython-311.pyc | Bin 0 -> 6815 bytes .../__pycache__/extension.cpython-311.pyc | Bin 0 -> 10196 bytes .../__pycache__/fancy_getopt.cpython-311.pyc | Bin 0 -> 17260 bytes .../__pycache__/file_util.cpython-311.pyc | Bin 0 -> 10704 bytes .../__pycache__/filelist.cpython-311.pyc | Bin 0 -> 17650 bytes .../__pycache__/log.cpython-311.pyc | Bin 0 -> 3950 bytes .../__pycache__/msvc9compiler.cpython-311.pyc | Bin 0 -> 33608 bytes .../__pycache__/msvccompiler.cpython-311.pyc | Bin 0 -> 27010 bytes .../__pycache__/py38compat.cpython-311.pyc | Bin 0 -> 642 bytes .../__pycache__/py39compat.cpython-311.pyc | Bin 0 -> 1010 bytes .../__pycache__/spawn.cpython-311.pyc | Bin 0 -> 4479 bytes .../__pycache__/sysconfig.cpython-311.pyc | Bin 0 -> 22006 bytes .../__pycache__/text_file.cpython-311.pyc | Bin 0 -> 11291 bytes .../__pycache__/unixccompiler.cpython-311.pyc | Bin 0 -> 16547 bytes .../__pycache__/util.cpython-311.pyc | Bin 0 -> 20901 bytes .../__pycache__/version.cpython-311.pyc | Bin 0 -> 11367 bytes .../versionpredicate.cpython-311.pyc | Bin 0 -> 7767 bytes .../setuptools/_distutils/_collections.py | 56 + .../setuptools/_distutils/_functools.py | 20 + .../setuptools/_distutils/_macos_compat.py | 12 + .../setuptools/_distutils/_msvccompiler.py | 572 ++ .../setuptools/_distutils/archive_util.py | 280 + .../setuptools/_distutils/bcppcompiler.py | 408 + .../setuptools/_distutils/ccompiler.py | 1220 +++ .../setuptools/_distutils/cmd.py | 436 + .../setuptools/_distutils/command/__init__.py | 25 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 562 bytes .../_framework_compat.cpython-311.pyc | Bin 0 -> 2803 bytes .../command/__pycache__/bdist.cpython-311.pyc | Bin 0 -> 6056 bytes .../__pycache__/bdist_dumb.cpython-311.pyc | Bin 0 -> 5781 bytes .../__pycache__/bdist_rpm.cpython-311.pyc | Bin 0 -> 23315 bytes .../command/__pycache__/build.cpython-311.pyc | Bin 0 -> 6111 bytes .../__pycache__/build_clib.cpython-311.pyc | Bin 0 -> 7814 bytes .../__pycache__/build_ext.cpython-311.pyc | Bin 0 -> 30356 bytes .../__pycache__/build_py.cpython-311.pyc | Bin 0 -> 17632 bytes .../__pycache__/build_scripts.cpython-311.pyc | Bin 0 -> 7883 bytes .../command/__pycache__/check.cpython-311.pyc | Bin 0 -> 7545 bytes .../command/__pycache__/clean.cpython-311.pyc | Bin 0 -> 3213 bytes .../__pycache__/config.cpython-311.pyc | Bin 0 -> 16276 bytes .../__pycache__/install.cpython-311.pyc | Bin 0 -> 29464 bytes .../__pycache__/install_data.cpython-311.pyc | Bin 0 -> 3798 bytes .../install_egg_info.cpython-311.pyc | Bin 0 -> 5224 bytes .../install_headers.cpython-311.pyc | Bin 0 -> 2381 bytes .../__pycache__/install_lib.cpython-311.pyc | Bin 0 -> 8713 bytes .../install_scripts.cpython-311.pyc | Bin 0 -> 3178 bytes .../__pycache__/py37compat.cpython-311.pyc | Bin 0 -> 1559 bytes .../__pycache__/register.cpython-311.pyc | Bin 0 -> 15545 bytes .../command/__pycache__/sdist.cpython-311.pyc | Bin 0 -> 23853 bytes .../__pycache__/upload.cpython-311.pyc | Bin 0 -> 10494 bytes .../_distutils/command/_framework_compat.py | 55 + .../setuptools/_distutils/command/bdist.py | 157 + .../_distutils/command/bdist_dumb.py | 144 + .../_distutils/command/bdist_rpm.py | 615 ++ .../setuptools/_distutils/command/build.py | 153 + .../_distutils/command/build_clib.py | 208 + .../_distutils/command/build_ext.py | 787 ++ .../setuptools/_distutils/command/build_py.py | 407 + .../_distutils/command/build_scripts.py | 173 + .../setuptools/_distutils/command/check.py | 151 + .../setuptools/_distutils/command/clean.py | 76 + .../setuptools/_distutils/command/config.py | 377 + .../setuptools/_distutils/command/install.py | 814 ++ .../_distutils/command/install_data.py | 84 + .../_distutils/command/install_egg_info.py | 91 + .../_distutils/command/install_headers.py | 45 + .../_distutils/command/install_lib.py | 238 + .../_distutils/command/install_scripts.py | 61 + .../_distutils/command/py37compat.py | 31 + .../setuptools/_distutils/command/register.py | 319 + .../setuptools/_distutils/command/sdist.py | 531 + .../setuptools/_distutils/command/upload.py | 205 + .../setuptools/_distutils/config.py | 139 + .../setuptools/_distutils/core.py | 291 + .../setuptools/_distutils/cygwinccompiler.py | 364 + .../setuptools/_distutils/debug.py | 5 + .../setuptools/_distutils/dep_util.py | 96 + .../setuptools/_distutils/dir_util.py | 243 + .../setuptools/_distutils/dist.py | 1286 +++ .../setuptools/_distutils/errors.py | 127 + .../setuptools/_distutils/extension.py | 248 + .../setuptools/_distutils/fancy_getopt.py | 470 + .../setuptools/_distutils/file_util.py | 249 + .../setuptools/_distutils/filelist.py | 371 + .../setuptools/_distutils/log.py | 80 + .../setuptools/_distutils/msvc9compiler.py | 832 ++ .../setuptools/_distutils/msvccompiler.py | 695 ++ .../setuptools/_distutils/py38compat.py | 8 + .../setuptools/_distutils/py39compat.py | 22 + .../setuptools/_distutils/spawn.py | 109 + .../setuptools/_distutils/sysconfig.py | 558 ++ .../setuptools/_distutils/text_file.py | 287 + .../setuptools/_distutils/unixccompiler.py | 401 + .../setuptools/_distutils/util.py | 513 + .../setuptools/_distutils/version.py | 358 + .../setuptools/_distutils/versionpredicate.py | 175 + .../site-packages/setuptools/_entry_points.py | 86 + .venv/Lib/site-packages/setuptools/_imp.py | 82 + .../site-packages/setuptools/_importlib.py | 47 + .../site-packages/setuptools/_itertools.py | 23 + .venv/Lib/site-packages/setuptools/_path.py | 29 + .venv/Lib/site-packages/setuptools/_reqs.py | 19 + .../setuptools/_vendor/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 213 bytes .../__pycache__/ordered_set.cpython-311.pyc | Bin 0 -> 21799 bytes .../typing_extensions.cpython-311.pyc | Bin 0 -> 107630 bytes .../_vendor/__pycache__/zipp.cpython-311.pyc | Bin 0 -> 16006 bytes .../_vendor/importlib_metadata/__init__.py | 1047 ++ .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 58252 bytes .../__pycache__/_adapters.cpython-311.pyc | Bin 0 -> 3865 bytes .../__pycache__/_collections.cpython-311.pyc | Bin 0 -> 2212 bytes .../__pycache__/_compat.cpython-311.pyc | Bin 0 -> 2734 bytes .../__pycache__/_functools.cpython-311.pyc | Bin 0 -> 3652 bytes .../__pycache__/_itertools.cpython-311.pyc | Bin 0 -> 2615 bytes .../__pycache__/_meta.cpython-311.pyc | Bin 0 -> 3019 bytes .../__pycache__/_text.cpython-311.pyc | Bin 0 -> 4410 bytes .../_vendor/importlib_metadata/_adapters.py | 68 + .../importlib_metadata/_collections.py | 30 + .../_vendor/importlib_metadata/_compat.py | 71 + .../_vendor/importlib_metadata/_functools.py | 104 + .../_vendor/importlib_metadata/_itertools.py | 73 + .../_vendor/importlib_metadata/_meta.py | 48 + .../_vendor/importlib_metadata/_text.py | 99 + .../_vendor/importlib_resources/__init__.py | 36 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 847 bytes .../__pycache__/_adapters.cpython-311.pyc | Bin 0 -> 10764 bytes .../__pycache__/_common.cpython-311.pyc | Bin 0 -> 4291 bytes .../__pycache__/_compat.cpython-311.pyc | Bin 0 -> 5576 bytes .../__pycache__/_itertools.cpython-311.pyc | Bin 0 -> 1409 bytes .../__pycache__/_legacy.cpython-311.pyc | Bin 0 -> 6507 bytes .../__pycache__/abc.cpython-311.pyc | Bin 0 -> 7508 bytes .../__pycache__/readers.cpython-311.pyc | Bin 0 -> 8382 bytes .../__pycache__/simple.cpython-311.pyc | Bin 0 -> 6404 bytes .../_vendor/importlib_resources/_adapters.py | 170 + .../_vendor/importlib_resources/_common.py | 104 + .../_vendor/importlib_resources/_compat.py | 98 + .../_vendor/importlib_resources/_itertools.py | 35 + .../_vendor/importlib_resources/_legacy.py | 121 + .../_vendor/importlib_resources/abc.py | 137 + .../_vendor/importlib_resources/readers.py | 122 + .../_vendor/importlib_resources/simple.py | 116 + .../setuptools/_vendor/jaraco/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 220 bytes .../__pycache__/context.cpython-311.pyc | Bin 0 -> 9443 bytes .../__pycache__/functools.cpython-311.pyc | Bin 0 -> 20300 bytes .../setuptools/_vendor/jaraco/context.py | 213 + .../setuptools/_vendor/jaraco/functools.py | 525 + .../_vendor/jaraco/text/__init__.py | 599 ++ .../text/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 26614 bytes .../_vendor/more_itertools/__init__.py | 4 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 313 bytes .../__pycache__/more.cpython-311.pyc | Bin 0 -> 149200 bytes .../__pycache__/recipes.cpython-311.pyc | Bin 0 -> 23782 bytes .../setuptools/_vendor/more_itertools/more.py | 3824 ++++++++ .../_vendor/more_itertools/recipes.py | 620 ++ .../setuptools/_vendor/ordered_set.py | 488 + .../setuptools/_vendor/packaging/__about__.py | 26 + .../setuptools/_vendor/packaging/__init__.py | 25 + .../__pycache__/__about__.cpython-311.pyc | Bin 0 -> 664 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 585 bytes .../__pycache__/_manylinux.cpython-311.pyc | Bin 0 -> 13251 bytes .../__pycache__/_musllinux.cpython-311.pyc | Bin 0 -> 8019 bytes .../__pycache__/_structures.cpython-311.pyc | Bin 0 -> 3707 bytes .../__pycache__/markers.cpython-311.pyc | Bin 0 -> 16553 bytes .../__pycache__/requirements.cpython-311.pyc | Bin 0 -> 7668 bytes .../__pycache__/specifiers.cpython-311.pyc | Bin 0 -> 34385 bytes .../__pycache__/tags.cpython-311.pyc | Bin 0 -> 21370 bytes .../__pycache__/utils.cpython-311.pyc | Bin 0 -> 6705 bytes .../__pycache__/version.cpython-311.pyc | Bin 0 -> 21897 bytes .../_vendor/packaging/_manylinux.py | 301 + .../_vendor/packaging/_musllinux.py | 136 + .../_vendor/packaging/_structures.py | 61 + .../setuptools/_vendor/packaging/markers.py | 304 + .../_vendor/packaging/requirements.py | 146 + .../_vendor/packaging/specifiers.py | 802 ++ .../setuptools/_vendor/packaging/tags.py | 487 + .../setuptools/_vendor/packaging/utils.py | 136 + .../setuptools/_vendor/packaging/version.py | 504 + .../setuptools/_vendor/pyparsing/__init__.py | 331 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 8358 bytes .../__pycache__/actions.cpython-311.pyc | Bin 0 -> 8484 bytes .../__pycache__/common.cpython-311.pyc | Bin 0 -> 14806 bytes .../__pycache__/core.cpython-311.pyc | Bin 0 -> 277658 bytes .../__pycache__/exceptions.cpython-311.pyc | Bin 0 -> 12948 bytes .../__pycache__/helpers.cpython-311.pyc | Bin 0 -> 53649 bytes .../__pycache__/results.cpython-311.pyc | Bin 0 -> 36332 bytes .../__pycache__/testing.cpython-311.pyc | Bin 0 -> 19528 bytes .../__pycache__/unicode.cpython-311.pyc | Bin 0 -> 15386 bytes .../__pycache__/util.cpython-311.pyc | Bin 0 -> 14285 bytes .../setuptools/_vendor/pyparsing/actions.py | 207 + .../setuptools/_vendor/pyparsing/common.py | 424 + .../setuptools/_vendor/pyparsing/core.py | 5814 +++++++++++ .../_vendor/pyparsing/diagram/__init__.py | 642 ++ .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 28021 bytes .../_vendor/pyparsing/exceptions.py | 267 + .../setuptools/_vendor/pyparsing/helpers.py | 1088 +++ .../setuptools/_vendor/pyparsing/results.py | 760 ++ .../setuptools/_vendor/pyparsing/testing.py | 331 + .../setuptools/_vendor/pyparsing/unicode.py | 352 + .../setuptools/_vendor/pyparsing/util.py | 235 + .../setuptools/_vendor/tomli/__init__.py | 11 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 435 bytes .../tomli/__pycache__/_parser.cpython-311.pyc | Bin 0 -> 30874 bytes .../tomli/__pycache__/_re.cpython-311.pyc | Bin 0 -> 4514 bytes .../tomli/__pycache__/_types.cpython-311.pyc | Bin 0 -> 427 bytes .../setuptools/_vendor/tomli/_parser.py | 691 ++ .../setuptools/_vendor/tomli/_re.py | 107 + .../setuptools/_vendor/tomli/_types.py | 10 + .../setuptools/_vendor/typing_extensions.py | 2296 +++++ .../site-packages/setuptools/_vendor/zipp.py | 329 + .../site-packages/setuptools/archive_util.py | 213 + .../site-packages/setuptools/build_meta.py | 511 + .venv/Lib/site-packages/setuptools/cli-32.exe | Bin 0 -> 65536 bytes .venv/Lib/site-packages/setuptools/cli-64.exe | Bin 0 -> 74752 bytes .../site-packages/setuptools/cli-arm64.exe | Bin 0 -> 137216 bytes .venv/Lib/site-packages/setuptools/cli.exe | Bin 0 -> 65536 bytes .../setuptools/command/__init__.py | 12 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 654 bytes .../command/__pycache__/alias.cpython-311.pyc | Bin 0 -> 3921 bytes .../__pycache__/bdist_egg.cpython-311.pyc | Bin 0 -> 25603 bytes .../__pycache__/bdist_rpm.cpython-311.pyc | Bin 0 -> 2209 bytes .../command/__pycache__/build.cpython-311.pyc | Bin 0 -> 7015 bytes .../__pycache__/build_clib.cpython-311.pyc | Bin 0 -> 4142 bytes .../__pycache__/build_ext.cpython-311.pyc | Bin 0 -> 22029 bytes .../__pycache__/build_py.cpython-311.pyc | Bin 0 -> 23195 bytes .../__pycache__/develop.cpython-311.pyc | Bin 0 -> 10937 bytes .../__pycache__/dist_info.cpython-311.pyc | Bin 0 -> 7999 bytes .../__pycache__/easy_install.cpython-311.pyc | Bin 0 -> 119354 bytes .../editable_wheel.cpython-311.pyc | Bin 0 -> 51432 bytes .../__pycache__/egg_info.cpython-311.pyc | Bin 0 -> 39852 bytes .../__pycache__/install.cpython-311.pyc | Bin 0 -> 6834 bytes .../install_egg_info.cpython-311.pyc | Bin 0 -> 4147 bytes .../__pycache__/install_lib.cpython-311.pyc | Bin 0 -> 6429 bytes .../install_scripts.cpython-311.pyc | Bin 0 -> 4298 bytes .../__pycache__/py36compat.cpython-311.pyc | Bin 0 -> 8055 bytes .../__pycache__/register.cpython-311.pyc | Bin 0 -> 1145 bytes .../__pycache__/rotate.cpython-311.pyc | Bin 0 -> 4205 bytes .../__pycache__/saveopts.cpython-311.pyc | Bin 0 -> 1385 bytes .../command/__pycache__/sdist.cpython-311.pyc | Bin 0 -> 13457 bytes .../__pycache__/setopt.cpython-311.pyc | Bin 0 -> 7697 bytes .../command/__pycache__/test.cpython-311.pyc | Bin 0 -> 14638 bytes .../__pycache__/upload.cpython-311.pyc | Bin 0 -> 1109 bytes .../__pycache__/upload_docs.cpython-311.pyc | Bin 0 -> 11960 bytes .../site-packages/setuptools/command/alias.py | 78 + .../setuptools/command/bdist_egg.py | 457 + .../setuptools/command/bdist_rpm.py | 40 + .../site-packages/setuptools/command/build.py | 146 + .../setuptools/command/build_clib.py | 101 + .../setuptools/command/build_ext.py | 383 + .../setuptools/command/build_py.py | 368 + .../setuptools/command/develop.py | 193 + .../setuptools/command/dist_info.py | 142 + .../setuptools/command/easy_install.py | 2312 +++++ .../setuptools/command/editable_wheel.py | 844 ++ .../setuptools/command/egg_info.py | 763 ++ .../setuptools/command/install.py | 139 + .../setuptools/command/install_egg_info.py | 63 + .../setuptools/command/install_lib.py | 122 + .../setuptools/command/install_scripts.py | 70 + .../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 | 210 + .../setuptools/command/setopt.py | 149 + .../site-packages/setuptools/command/test.py | 251 + .../setuptools/command/upload.py | 17 + .../setuptools/command/upload_docs.py | 213 + .../setuptools/config/__init__.py | 35 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 2049 bytes .../_apply_pyprojecttoml.cpython-311.pyc | Bin 0 -> 22552 bytes .../config/__pycache__/expand.cpython-311.pyc | Bin 0 -> 28263 bytes .../__pycache__/pyprojecttoml.cpython-311.pyc | Bin 0 -> 27461 bytes .../__pycache__/setupcfg.cpython-311.pyc | Bin 0 -> 33045 bytes .../setuptools/config/_apply_pyprojecttoml.py | 377 + .../config/_validate_pyproject/__init__.py | 34 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 2337 bytes .../error_reporting.cpython-311.pyc | Bin 0 -> 20228 bytes .../extra_validations.cpython-311.pyc | Bin 0 -> 1886 bytes .../fastjsonschema_exceptions.cpython-311.pyc | Bin 0 -> 3261 bytes ...fastjsonschema_validations.cpython-311.pyc | Bin 0 -> 192659 bytes .../__pycache__/formats.cpython-311.pyc | Bin 0 -> 14376 bytes .../_validate_pyproject/error_reporting.py | 318 + .../_validate_pyproject/extra_validations.py | 36 + .../fastjsonschema_exceptions.py | 51 + .../fastjsonschema_validations.py | 1035 ++ .../config/_validate_pyproject/formats.py | 259 + .../site-packages/setuptools/config/expand.py | 462 + .../setuptools/config/pyprojecttoml.py | 493 + .../setuptools/config/setupcfg.py | 762 ++ .../Lib/site-packages/setuptools/dep_util.py | 25 + .venv/Lib/site-packages/setuptools/depends.py | 176 + .../Lib/site-packages/setuptools/discovery.py | 600 ++ .venv/Lib/site-packages/setuptools/dist.py | 1222 +++ .venv/Lib/site-packages/setuptools/errors.py | 58 + .../Lib/site-packages/setuptools/extension.py | 148 + .../setuptools/extern/__init__.py | 76 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 4413 bytes .venv/Lib/site-packages/setuptools/glob.py | 167 + .venv/Lib/site-packages/setuptools/gui-32.exe | Bin 0 -> 65536 bytes .venv/Lib/site-packages/setuptools/gui-64.exe | Bin 0 -> 75264 bytes .../site-packages/setuptools/gui-arm64.exe | Bin 0 -> 137728 bytes .venv/Lib/site-packages/setuptools/gui.exe | Bin 0 -> 65536 bytes .../Lib/site-packages/setuptools/installer.py | 104 + .venv/Lib/site-packages/setuptools/launch.py | 36 + .venv/Lib/site-packages/setuptools/logging.py | 36 + .venv/Lib/site-packages/setuptools/monkey.py | 165 + .venv/Lib/site-packages/setuptools/msvc.py | 1703 ++++ .../site-packages/setuptools/namespaces.py | 107 + .../site-packages/setuptools/package_index.py | 1126 +++ .../site-packages/setuptools/py34compat.py | 13 + .venv/Lib/site-packages/setuptools/sandbox.py | 530 + .../setuptools/script (dev).tmpl | 6 + .../Lib/site-packages/setuptools/script.tmpl | 3 + .../site-packages/setuptools/unicode_utils.py | 42 + .venv/Lib/site-packages/setuptools/version.py | 6 + .venv/Lib/site-packages/setuptools/wheel.py | 222 + .../setuptools/windows_support.py | 29 + .../Lib/site-packages/sqlalchemy/__init__.py | 281 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 13245 bytes .../__pycache__/events.cpython-311.pyc | Bin 0 -> 682 bytes .../__pycache__/exc.cpython-311.pyc | Bin 0 -> 34773 bytes .../__pycache__/inspection.cpython-311.pyc | Bin 0 -> 5842 bytes .../__pycache__/log.cpython-311.pyc | Bin 0 -> 12317 bytes .../__pycache__/schema.cpython-311.pyc | Bin 0 -> 3188 bytes .../__pycache__/types.cpython-311.pyc | Bin 0 -> 3251 bytes .../sqlalchemy/connectors/__init__.py | 18 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 693 bytes .../__pycache__/pyodbc.cpython-311.pyc | Bin 0 -> 11196 bytes .../sqlalchemy/connectors/pyodbc.py | 247 + .../sqlalchemy/cyextension/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 217 bytes .../collections.cp311-win_amd64.pyd | Bin 0 -> 126464 bytes .../sqlalchemy/cyextension/collections.pyx | 403 + .../immutabledict.cp311-win_amd64.pyd | Bin 0 -> 55296 bytes .../sqlalchemy/cyextension/immutabledict.pxd | 2 + .../sqlalchemy/cyextension/immutabledict.pyx | 127 + .../processors.cp311-win_amd64.pyd | Bin 0 -> 35328 bytes .../sqlalchemy/cyextension/processors.pyx | 62 + .../resultproxy.cp311-win_amd64.pyd | Bin 0 -> 41472 bytes .../sqlalchemy/cyextension/resultproxy.pyx | 96 + .../cyextension/util.cp311-win_amd64.pyd | Bin 0 -> 50176 bytes .../sqlalchemy/cyextension/util.pyx | 85 + .../sqlalchemy/dialects/__init__.py | 61 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 2108 bytes .../sqlalchemy/dialects/mssql/__init__.py | 88 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 2181 bytes .../mssql/__pycache__/base.cpython-311.pyc | Bin 0 -> 158259 bytes .../information_schema.cpython-311.pyc | Bin 0 -> 9836 bytes .../mssql/__pycache__/json.cpython-311.pyc | Bin 0 -> 5839 bytes .../__pycache__/provision.cpython-311.pyc | Bin 0 -> 8264 bytes .../mssql/__pycache__/pymssql.cpython-311.pyc | Bin 0 -> 6689 bytes .../mssql/__pycache__/pyodbc.cpython-311.pyc | Bin 0 -> 32899 bytes .../sqlalchemy/dialects/mssql/base.py | 4009 ++++++++ .../dialects/mssql/information_schema.py | 253 + .../sqlalchemy/dialects/mssql/json.py | 127 + .../sqlalchemy/dialects/mssql/provision.py | 148 + .../sqlalchemy/dialects/mssql/pymssql.py | 125 + .../sqlalchemy/dialects/mssql/pyodbc.py | 738 ++ .../sqlalchemy/dialects/mysql/__init__.py | 101 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 2665 bytes .../__pycache__/aiomysql.cpython-311.pyc | Bin 0 -> 16682 bytes .../mysql/__pycache__/asyncmy.cpython-311.pyc | Bin 0 -> 18343 bytes .../mysql/__pycache__/base.cpython-311.pyc | Bin 0 -> 143285 bytes .../mysql/__pycache__/cymysql.cpython-311.pyc | Bin 0 -> 3359 bytes .../mysql/__pycache__/dml.cpython-311.pyc | Bin 0 -> 8088 bytes .../__pycache__/enumerated.cpython-311.pyc | Bin 0 -> 11269 bytes .../__pycache__/expression.cpython-311.pyc | Bin 0 -> 5403 bytes .../mysql/__pycache__/json.cpython-311.pyc | Bin 0 -> 3993 bytes .../mysql/__pycache__/mariadb.cpython-311.pyc | Bin 0 -> 1182 bytes .../mariadbconnector.cpython-311.pyc | Bin 0 -> 11206 bytes .../mysqlconnector.cpython-311.pyc | Bin 0 -> 9711 bytes .../mysql/__pycache__/mysqldb.cpython-311.pyc | Bin 0 -> 13068 bytes .../__pycache__/provision.cpython-311.pyc | Bin 0 -> 4859 bytes .../mysql/__pycache__/pymysql.cpython-311.pyc | Bin 0 -> 4189 bytes .../mysql/__pycache__/pyodbc.cpython-311.pyc | Bin 0 -> 5870 bytes .../__pycache__/reflection.cpython-311.pyc | Bin 0 -> 26962 bytes .../reserved_words.cpython-311.pyc | Bin 0 -> 4433 bytes .../mysql/__pycache__/types.cpython-311.pyc | Bin 0 -> 33659 bytes .../sqlalchemy/dialects/mysql/aiomysql.py | 317 + .../sqlalchemy/dialects/mysql/asyncmy.py | 329 + .../sqlalchemy/dialects/mysql/base.py | 3410 +++++++ .../sqlalchemy/dialects/mysql/cymysql.py | 84 + .../sqlalchemy/dialects/mysql/dml.py | 198 + .../sqlalchemy/dialects/mysql/enumerated.py | 244 + .../sqlalchemy/dialects/mysql/expression.py | 140 + .../sqlalchemy/dialects/mysql/json.py | 81 + .../sqlalchemy/dialects/mysql/mariadb.py | 27 + .../dialects/mysql/mariadbconnector.py | 237 + .../dialects/mysql/mysqlconnector.py | 179 + .../sqlalchemy/dialects/mysql/mysqldb.py | 308 + .../sqlalchemy/dialects/mysql/provision.py | 101 + .../sqlalchemy/dialects/mysql/pymysql.py | 101 + .../sqlalchemy/dialects/mysql/pyodbc.py | 138 + .../sqlalchemy/dialects/mysql/reflection.py | 672 ++ .../dialects/mysql/reserved_words.py | 567 ++ .../sqlalchemy/dialects/mysql/types.py | 773 ++ .../sqlalchemy/dialects/oracle/__init__.py | 62 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 1551 bytes .../oracle/__pycache__/base.cpython-311.pyc | Bin 0 -> 136405 bytes .../__pycache__/cx_oracle.cpython-311.pyc | Bin 0 -> 62721 bytes .../__pycache__/dictionary.cpython-311.pyc | Bin 0 -> 32403 bytes .../__pycache__/oracledb.cpython-311.pyc | Bin 0 -> 4658 bytes .../__pycache__/provision.cpython-311.pyc | Bin 0 -> 12701 bytes .../oracle/__pycache__/types.cpython-311.pyc | Bin 0 -> 12343 bytes .../sqlalchemy/dialects/oracle/base.py | 3234 +++++++ .../sqlalchemy/dialects/oracle/cx_oracle.py | 1491 +++ .../sqlalchemy/dialects/oracle/dictionary.py | 506 + .../sqlalchemy/dialects/oracle/oracledb.py | 110 + .../sqlalchemy/dialects/oracle/provision.py | 217 + .../sqlalchemy/dialects/oracle/types.py | 257 + .../dialects/postgresql/__init__.py | 163 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 4504 bytes .../_psycopg_common.cpython-311.pyc | Bin 0 -> 9163 bytes .../__pycache__/array.cpython-311.pyc | Bin 0 -> 17971 bytes .../__pycache__/asyncpg.cpython-311.pyc | Bin 0 -> 57206 bytes .../__pycache__/base.cpython-311.pyc | Bin 0 -> 197135 bytes .../__pycache__/dml.cpython-311.pyc | Bin 0 -> 11420 bytes .../__pycache__/ext.cpython-311.pyc | Bin 0 -> 20588 bytes .../__pycache__/hstore.cpython-311.pyc | Bin 0 -> 17071 bytes .../__pycache__/json.cpython-311.pyc | Bin 0 -> 15011 bytes .../__pycache__/named_types.cpython-311.pyc | Bin 0 -> 24284 bytes .../__pycache__/pg8000.cpython-311.pyc | Bin 0 -> 27947 bytes .../__pycache__/pg_catalog.cpython-311.pyc | Bin 0 -> 12971 bytes .../__pycache__/provision.cpython-311.pyc | Bin 0 -> 9189 bytes .../__pycache__/psycopg.cpython-311.pyc | Bin 0 -> 38706 bytes .../__pycache__/psycopg2.cpython-311.pyc | Bin 0 -> 36037 bytes .../__pycache__/psycopg2cffi.cpython-311.pyc | Bin 0 -> 2318 bytes .../__pycache__/ranges.cpython-311.pyc | Bin 0 -> 34210 bytes .../__pycache__/types.cpython-311.pyc | Bin 0 -> 11298 bytes .../dialects/postgresql/_psycopg_common.py | 197 + .../sqlalchemy/dialects/postgresql/array.py | 432 + .../sqlalchemy/dialects/postgresql/asyncpg.py | 1175 +++ .../sqlalchemy/dialects/postgresql/base.py | 4696 +++++++++ .../sqlalchemy/dialects/postgresql/dml.py | 289 + .../sqlalchemy/dialects/postgresql/ext.py | 493 + .../sqlalchemy/dialects/postgresql/hstore.py | 436 + .../sqlalchemy/dialects/postgresql/json.py | 390 + .../dialects/postgresql/named_types.py | 493 + .../sqlalchemy/dialects/postgresql/pg8000.py | 567 ++ .../dialects/postgresql/pg_catalog.py | 293 + .../dialects/postgresql/provision.py | 169 + .../sqlalchemy/dialects/postgresql/psycopg.py | 740 ++ .../dialects/postgresql/psycopg2.py | 856 ++ .../dialects/postgresql/psycopg2cffi.py | 61 + .../sqlalchemy/dialects/postgresql/ranges.py | 950 ++ .../sqlalchemy/dialects/postgresql/types.py | 293 + .../sqlalchemy/dialects/sqlite/__init__.py | 57 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 1392 bytes .../__pycache__/aiosqlite.cpython-311.pyc | Bin 0 -> 17899 bytes .../sqlite/__pycache__/base.cpython-311.pyc | Bin 0 -> 104387 bytes .../sqlite/__pycache__/dml.cpython-311.pyc | Bin 0 -> 9175 bytes .../sqlite/__pycache__/json.cpython-311.pyc | Bin 0 -> 4330 bytes .../__pycache__/provision.cpython-311.pyc | Bin 0 -> 8001 bytes .../__pycache__/pysqlcipher.cpython-311.pyc | Bin 0 -> 6615 bytes .../__pycache__/pysqlite.cpython-311.pyc | Bin 0 -> 33673 bytes .../sqlalchemy/dialects/sqlite/aiosqlite.py | 359 + .../sqlalchemy/dialects/sqlite/base.py | 2777 ++++++ .../sqlalchemy/dialects/sqlite/dml.py | 221 + .../sqlalchemy/dialects/sqlite/json.py | 86 + .../sqlalchemy/dialects/sqlite/provision.py | 192 + .../sqlalchemy/dialects/sqlite/pysqlcipher.py | 155 + .../sqlalchemy/dialects/sqlite/pysqlite.py | 754 ++ .../dialects/type_migration_guidelines.txt | 145 + .../sqlalchemy/engine/__init__.py | 62 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 2972 bytes .../_py_processors.cpython-311.pyc | Bin 0 -> 5182 bytes .../__pycache__/_py_row.cpython-311.pyc | Bin 0 -> 6781 bytes .../__pycache__/_py_util.cpython-311.pyc | Bin 0 -> 2573 bytes .../engine/__pycache__/base.cpython-311.pyc | Bin 0 -> 132152 bytes .../characteristics.cpython-311.pyc | Bin 0 -> 3929 bytes .../engine/__pycache__/create.cpython-311.pyc | Bin 0 -> 34826 bytes .../engine/__pycache__/cursor.cpython-311.pyc | Bin 0 -> 85428 bytes .../__pycache__/default.cpython-311.pyc | Bin 0 -> 92648 bytes .../engine/__pycache__/events.cpython-311.pyc | Bin 0 -> 40585 bytes .../__pycache__/interfaces.cpython-311.pyc | Bin 0 -> 103580 bytes .../engine/__pycache__/mock.cpython-311.pyc | Bin 0 -> 6279 bytes .../__pycache__/processors.cpython-311.pyc | Bin 0 -> 1675 bytes .../__pycache__/reflection.cpython-311.pyc | Bin 0 -> 85635 bytes .../engine/__pycache__/result.cpython-311.pyc | Bin 0 -> 101248 bytes .../engine/__pycache__/row.cpython-311.pyc | Bin 0 -> 17868 bytes .../__pycache__/strategies.cpython-311.pyc | Bin 0 -> 664 bytes .../engine/__pycache__/url.cpython-311.pyc | Bin 0 -> 36595 bytes .../engine/__pycache__/util.cpython-311.pyc | Bin 0 -> 7604 bytes .../sqlalchemy/engine/_py_processors.py | 136 + .../sqlalchemy/engine/_py_row.py | 122 + .../sqlalchemy/engine/_py_util.py | 68 + .../site-packages/sqlalchemy/engine/base.py | 3361 +++++++ .../sqlalchemy/engine/characteristics.py | 75 + .../site-packages/sqlalchemy/engine/create.py | 861 ++ .../site-packages/sqlalchemy/engine/cursor.py | 2155 +++++ .../sqlalchemy/engine/default.py | 2311 +++++ .../site-packages/sqlalchemy/engine/events.py | 952 ++ .../sqlalchemy/engine/interfaces.py | 3406 +++++++ .../site-packages/sqlalchemy/engine/mock.py | 129 + .../sqlalchemy/engine/processors.py | 61 + .../sqlalchemy/engine/reflection.py | 2089 ++++ .../site-packages/sqlalchemy/engine/result.py | 2403 +++++ .../site-packages/sqlalchemy/engine/row.py | 365 + .../sqlalchemy/engine/strategies.py | 19 + .../site-packages/sqlalchemy/engine/url.py | 907 ++ .../site-packages/sqlalchemy/engine/util.py | 166 + .../sqlalchemy/event/__init__.py | 25 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 1110 bytes .../event/__pycache__/api.cpython-311.pyc | Bin 0 -> 9500 bytes .../event/__pycache__/attr.cpython-311.pyc | Bin 0 -> 33307 bytes .../event/__pycache__/base.cpython-311.pyc | Bin 0 -> 21909 bytes .../event/__pycache__/legacy.cpython-311.pyc | Bin 0 -> 10106 bytes .../__pycache__/registry.cpython-311.pyc | Bin 0 -> 13455 bytes .../Lib/site-packages/sqlalchemy/event/api.py | 225 + .../site-packages/sqlalchemy/event/attr.py | 641 ++ .../site-packages/sqlalchemy/event/base.py | 465 + .../site-packages/sqlalchemy/event/legacy.py | 247 + .../sqlalchemy/event/registry.py | 387 + .venv/Lib/site-packages/sqlalchemy/events.py | 17 + .venv/Lib/site-packages/sqlalchemy/exc.py | 833 ++ .../site-packages/sqlalchemy/ext/__init__.py | 11 + .../ext/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 384 bytes .../associationproxy.cpython-311.pyc | Bin 0 -> 93231 bytes .../ext/__pycache__/automap.cpython-311.pyc | Bin 0 -> 58898 bytes .../ext/__pycache__/baked.cpython-311.pyc | Bin 0 -> 25115 bytes .../ext/__pycache__/compiler.cpython-311.pyc | Bin 0 -> 21030 bytes .../horizontal_shard.cpython-311.pyc | Bin 0 -> 19014 bytes .../ext/__pycache__/hybrid.cpython-311.pyc | Bin 0 -> 62158 bytes .../ext/__pycache__/indexable.cpython-311.pyc | Bin 0 -> 12665 bytes .../instrumentation.cpython-311.pyc | Bin 0 -> 21586 bytes .../ext/__pycache__/mutable.cpython-311.pyc | Bin 0 -> 50943 bytes .../__pycache__/orderinglist.cpython-311.pyc | Bin 0 -> 18772 bytes .../__pycache__/serializer.cpython-311.pyc | Bin 0 -> 8193 bytes .../sqlalchemy/ext/associationproxy.py | 2006 ++++ .../sqlalchemy/ext/asyncio/__init__.py | 24 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 1204 bytes .../asyncio/__pycache__/base.cpython-311.pyc | Bin 0 -> 12262 bytes .../__pycache__/engine.cpython-311.pyc | Bin 0 -> 57023 bytes .../asyncio/__pycache__/exc.cpython-311.pyc | Bin 0 -> 1202 bytes .../__pycache__/result.cpython-311.pyc | Bin 0 -> 39346 bytes .../__pycache__/scoping.cpython-311.pyc | Bin 0 -> 53793 bytes .../__pycache__/session.cpython-311.pyc | Bin 0 -> 69315 bytes .../sqlalchemy/ext/asyncio/base.py | 285 + .../sqlalchemy/ext/asyncio/engine.py | 1420 +++ .../sqlalchemy/ext/asyncio/exc.py | 21 + .../sqlalchemy/ext/asyncio/result.py | 976 ++ .../sqlalchemy/ext/asyncio/scoping.py | 1512 +++ .../sqlalchemy/ext/asyncio/session.py | 1826 ++++ .../site-packages/sqlalchemy/ext/automap.py | 1660 ++++ .../Lib/site-packages/sqlalchemy/ext/baked.py | 574 ++ .../site-packages/sqlalchemy/ext/compiler.py | 555 ++ .../sqlalchemy/ext/declarative/__init__.py | 65 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 2265 bytes .../__pycache__/extensions.cpython-311.pyc | Bin 0 -> 21295 bytes .../sqlalchemy/ext/declarative/extensions.py | 518 + .../sqlalchemy/ext/horizontal_shard.py | 484 + .../site-packages/sqlalchemy/ext/hybrid.py | 1526 +++ .../site-packages/sqlalchemy/ext/indexable.py | 341 + .../sqlalchemy/ext/instrumentation.py | 452 + .../site-packages/sqlalchemy/ext/mutable.py | 1078 +++ .../sqlalchemy/ext/mypy/__init__.py | 0 .../mypy/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 214 bytes .../mypy/__pycache__/apply.cpython-311.pyc | Bin 0 -> 11095 bytes .../__pycache__/decl_class.cpython-311.pyc | Bin 0 -> 15923 bytes .../mypy/__pycache__/infer.cpython-311.pyc | Bin 0 -> 16022 bytes .../mypy/__pycache__/names.cpython-311.pyc | Bin 0 -> 11695 bytes .../mypy/__pycache__/plugin.cpython-311.pyc | Bin 0 -> 13061 bytes .../ext/mypy/__pycache__/util.cpython-311.pyc | Bin 0 -> 14012 bytes .../sqlalchemy/ext/mypy/apply.py | 320 + .../sqlalchemy/ext/mypy/decl_class.py | 518 + .../sqlalchemy/ext/mypy/infer.py | 592 ++ .../sqlalchemy/ext/mypy/names.py | 343 + .../sqlalchemy/ext/mypy/plugin.py | 304 + .../site-packages/sqlalchemy/ext/mypy/util.py | 323 + .../sqlalchemy/ext/orderinglist.py | 416 + .../sqlalchemy/ext/serializer.py | 185 + .../sqlalchemy/future/__init__.py | 16 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 543 bytes .../future/__pycache__/engine.cpython-311.pyc | Bin 0 -> 461 bytes .../site-packages/sqlalchemy/future/engine.py | 15 + .../site-packages/sqlalchemy/inspection.py | 147 + .venv/Lib/site-packages/sqlalchemy/log.py | 291 + .../site-packages/sqlalchemy/orm/__init__.py | 171 + .../orm/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 8568 bytes .../_orm_constructors.cpython-311.pyc | Bin 0 -> 99812 bytes .../orm/__pycache__/_typing.cpython-311.pyc | Bin 0 -> 7850 bytes .../__pycache__/attributes.cpython-311.pyc | Bin 0 -> 103332 bytes .../orm/__pycache__/base.cpython-311.pyc | Bin 0 -> 31690 bytes .../bulk_persistence.cpython-311.pyc | Bin 0 -> 69430 bytes .../__pycache__/clsregistry.cpython-311.pyc | Bin 0 -> 26879 bytes .../__pycache__/collections.cpython-311.pyc | Bin 0 -> 67116 bytes .../orm/__pycache__/context.cpython-311.pyc | Bin 0 -> 101377 bytes .../orm/__pycache__/decl_api.cpython-311.pyc | Bin 0 -> 69918 bytes .../orm/__pycache__/decl_base.cpython-311.pyc | Bin 0 -> 76442 bytes .../__pycache__/dependency.cpython-311.pyc | Bin 0 -> 44229 bytes .../descriptor_props.cpython-311.pyc | Bin 0 -> 53480 bytes .../orm/__pycache__/dynamic.cpython-311.pyc | Bin 0 -> 12508 bytes .../orm/__pycache__/evaluator.cpython-311.pyc | Bin 0 -> 17672 bytes .../orm/__pycache__/events.cpython-311.pyc | Bin 0 -> 139958 bytes .../orm/__pycache__/exc.cpython-311.pyc | Bin 0 -> 11066 bytes .../orm/__pycache__/identity.cpython-311.pyc | Bin 0 -> 13946 bytes .../instrumentation.cpython-311.pyc | Bin 0 -> 33784 bytes .../__pycache__/interfaces.cpython-311.pyc | Bin 0 -> 54987 bytes .../orm/__pycache__/loading.cpython-311.pyc | Bin 0 -> 51456 bytes .../mapped_collection.cpython-311.pyc | Bin 0 -> 23472 bytes .../orm/__pycache__/mapper.cpython-311.pyc | Bin 0 -> 174550 bytes .../__pycache__/path_registry.cpython-311.pyc | Bin 0 -> 33372 bytes .../__pycache__/persistence.cpython-311.pyc | Bin 0 -> 49788 bytes .../__pycache__/properties.cpython-311.pyc | Bin 0 -> 32372 bytes .../orm/__pycache__/query.cpython-311.pyc | Bin 0 -> 132130 bytes .../__pycache__/relationships.cpython-311.pyc | Bin 0 -> 132238 bytes .../orm/__pycache__/scoping.cpython-311.pyc | Bin 0 -> 80621 bytes .../orm/__pycache__/session.cpython-311.pyc | Bin 0 -> 199742 bytes .../orm/__pycache__/state.cpython-311.pyc | Bin 0 -> 47042 bytes .../__pycache__/state_changes.cpython-311.pyc | Bin 0 -> 7350 bytes .../__pycache__/strategies.cpython-311.pyc | Bin 0 -> 109790 bytes .../strategy_options.cpython-311.pyc | Bin 0 -> 87373 bytes .../orm/__pycache__/sync.cpython-311.pyc | Bin 0 -> 6934 bytes .../__pycache__/unitofwork.cpython-311.pyc | Bin 0 -> 37090 bytes .../orm/__pycache__/util.cpython-311.pyc | Bin 0 -> 91947 bytes .../orm/__pycache__/writeonly.cpython-311.pyc | Bin 0 -> 27008 bytes .../sqlalchemy/orm/_orm_constructors.py | 2474 +++++ .../site-packages/sqlalchemy/orm/_typing.py | 191 + .../sqlalchemy/orm/attributes.py | 2826 ++++++ .../Lib/site-packages/sqlalchemy/orm/base.py | 963 ++ .../sqlalchemy/orm/bulk_persistence.py | 2019 ++++ .../sqlalchemy/orm/clsregistry.py | 573 ++ .../sqlalchemy/orm/collections.py | 1577 +++ .../site-packages/sqlalchemy/orm/context.py | 3160 ++++++ .../site-packages/sqlalchemy/orm/decl_api.py | 1858 ++++ .../site-packages/sqlalchemy/orm/decl_base.py | 2163 +++++ .../sqlalchemy/orm/dependency.py | 1294 +++ .../sqlalchemy/orm/descriptor_props.py | 1076 +++ .../site-packages/sqlalchemy/orm/dynamic.py | 276 + .../site-packages/sqlalchemy/orm/evaluator.py | 368 + .../site-packages/sqlalchemy/orm/events.py | 3251 +++++++ .venv/Lib/site-packages/sqlalchemy/orm/exc.py | 227 + .../site-packages/sqlalchemy/orm/identity.py | 302 + .../sqlalchemy/orm/instrumentation.py | 757 ++ .../sqlalchemy/orm/interfaces.py | 1440 +++ .../site-packages/sqlalchemy/orm/loading.py | 1638 ++++ .../sqlalchemy/orm/mapped_collection.py | 549 ++ .../site-packages/sqlalchemy/orm/mapper.py | 4392 +++++++++ .../sqlalchemy/orm/path_registry.py | 778 ++ .../sqlalchemy/orm/persistence.py | 1755 ++++ .../sqlalchemy/orm/properties.py | 808 ++ .../Lib/site-packages/sqlalchemy/orm/query.py | 3419 +++++++ .../sqlalchemy/orm/relationships.py | 3436 +++++++ .../site-packages/sqlalchemy/orm/scoping.py | 2075 ++++ .../site-packages/sqlalchemy/orm/session.py | 5099 ++++++++++ .../Lib/site-packages/sqlalchemy/orm/state.py | 1130 +++ .../sqlalchemy/orm/state_changes.py | 193 + .../sqlalchemy/orm/strategies.py | 3367 +++++++ .../sqlalchemy/orm/strategy_options.py | 2461 +++++ .../Lib/site-packages/sqlalchemy/orm/sync.py | 164 + .../sqlalchemy/orm/unitofwork.py | 798 ++ .../Lib/site-packages/sqlalchemy/orm/util.py | 2390 +++++ .../site-packages/sqlalchemy/orm/writeonly.py | 619 ++ .../site-packages/sqlalchemy/pool/__init__.py | 44 + .../pool/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 1889 bytes .../pool/__pycache__/base.cpython-311.pyc | Bin 0 -> 59328 bytes .../pool/__pycache__/events.cpython-311.pyc | Bin 0 -> 14435 bytes .../pool/__pycache__/impl.cpython-311.pyc | Bin 0 -> 26286 bytes .../Lib/site-packages/sqlalchemy/pool/base.py | 1521 +++ .../site-packages/sqlalchemy/pool/events.py | 370 + .../Lib/site-packages/sqlalchemy/pool/impl.py | 551 ++ .venv/Lib/site-packages/sqlalchemy/py.typed | 0 .venv/Lib/site-packages/sqlalchemy/schema.py | 70 + .../site-packages/sqlalchemy/sql/__init__.py | 142 + .../sql/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 6343 bytes .../_dml_constructors.cpython-311.pyc | Bin 0 -> 4314 bytes .../_elements_constructors.cpython-311.pyc | Bin 0 -> 64738 bytes .../__pycache__/_orm_types.cpython-311.pyc | Bin 0 -> 689 bytes .../sql/__pycache__/_py_util.cpython-311.pyc | Bin 0 -> 3362 bytes .../_selectable_constructors.cpython-311.pyc | Bin 0 -> 21618 bytes .../sql/__pycache__/_typing.cpython-311.pyc | Bin 0 -> 13102 bytes .../__pycache__/annotation.cpython-311.pyc | Bin 0 -> 22592 bytes .../sql/__pycache__/base.cpython-311.pyc | Bin 0 -> 106911 bytes .../sql/__pycache__/cache_key.cpython-311.pyc | Bin 0 -> 38840 bytes .../sql/__pycache__/coercions.cpython-311.pyc | Bin 0 -> 53610 bytes .../sql/__pycache__/compiler.cpython-311.pyc | Bin 0 -> 281251 bytes .../sql/__pycache__/crud.cpython-311.pyc | Bin 0 -> 47537 bytes .../sql/__pycache__/ddl.cpython-311.pyc | Bin 0 -> 63223 bytes .../default_comparator.cpython-311.pyc | Bin 0 -> 18119 bytes .../sql/__pycache__/dml.cpython-311.pyc | Bin 0 -> 77207 bytes .../sql/__pycache__/elements.cpython-311.pyc | Bin 0 -> 210523 bytes .../sql/__pycache__/events.cpython-311.pyc | Bin 0 -> 19375 bytes .../__pycache__/expression.cpython-311.pyc | Bin 0 -> 7148 bytes .../sql/__pycache__/functions.cpython-311.pyc | Bin 0 -> 72961 bytes .../sql/__pycache__/lambdas.cpython-311.pyc | Bin 0 -> 59607 bytes .../sql/__pycache__/naming.cpython-311.pyc | Bin 0 -> 9214 bytes .../sql/__pycache__/operators.cpython-311.pyc | Bin 0 -> 91125 bytes .../sql/__pycache__/roles.cpython-311.pyc | Bin 0 -> 14882 bytes .../sql/__pycache__/schema.cpython-311.pyc | Bin 0 -> 254302 bytes .../__pycache__/selectable.cpython-311.pyc | Bin 0 -> 271435 bytes .../sql/__pycache__/sqltypes.cpython-311.pyc | Bin 0 -> 157921 bytes .../__pycache__/traversals.cpython-311.pyc | Bin 0 -> 49279 bytes .../sql/__pycache__/type_api.cpython-311.pyc | Bin 0 -> 90291 bytes .../sql/__pycache__/util.cpython-311.pyc | Bin 0 -> 59963 bytes .../sql/__pycache__/visitors.cpython-311.pyc | Bin 0 -> 38723 bytes .../sqlalchemy/sql/_dml_constructors.py | 140 + .../sqlalchemy/sql/_elements_constructors.py | 1802 ++++ .../sqlalchemy/sql/_orm_types.py | 20 + .../site-packages/sqlalchemy/sql/_py_util.py | 76 + .../sql/_selectable_constructors.py | 642 ++ .../site-packages/sqlalchemy/sql/_typing.py | 377 + .../sqlalchemy/sql/annotation.py | 575 ++ .../Lib/site-packages/sqlalchemy/sql/base.py | 2189 +++++ .../site-packages/sqlalchemy/sql/cache_key.py | 1024 ++ .../site-packages/sqlalchemy/sql/coercions.py | 1410 +++ .../site-packages/sqlalchemy/sql/compiler.py | 7634 +++++++++++++++ .../Lib/site-packages/sqlalchemy/sql/crud.py | 1655 ++++ .venv/Lib/site-packages/sqlalchemy/sql/ddl.py | 1384 +++ .../sqlalchemy/sql/default_comparator.py | 553 ++ .venv/Lib/site-packages/sqlalchemy/sql/dml.py | 1833 ++++ .../site-packages/sqlalchemy/sql/elements.py | 5308 ++++++++++ .../site-packages/sqlalchemy/sql/events.py | 455 + .../sqlalchemy/sql/expression.py | 160 + .../site-packages/sqlalchemy/sql/functions.py | 1799 ++++ .../site-packages/sqlalchemy/sql/lambdas.py | 1453 +++ .../site-packages/sqlalchemy/sql/naming.py | 213 + .../site-packages/sqlalchemy/sql/operators.py | 2528 +++++ .../Lib/site-packages/sqlalchemy/sql/roles.py | 324 + .../site-packages/sqlalchemy/sql/schema.py | 6086 ++++++++++++ .../sqlalchemy/sql/selectable.py | 6922 +++++++++++++ .../site-packages/sqlalchemy/sql/sqltypes.py | 3838 ++++++++ .../sqlalchemy/sql/traversals.py | 1023 ++ .../site-packages/sqlalchemy/sql/type_api.py | 2363 +++++ .../Lib/site-packages/sqlalchemy/sql/util.py | 1501 +++ .../site-packages/sqlalchemy/sql/visitors.py | 1181 +++ .../sqlalchemy/testing/__init__.py | 95 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 4483 bytes .../__pycache__/assertions.cpython-311.pyc | Bin 0 -> 49535 bytes .../__pycache__/assertsql.cpython-311.pyc | Bin 0 -> 22350 bytes .../__pycache__/asyncio.cpython-311.pyc | Bin 0 -> 4235 bytes .../__pycache__/config.cpython-311.pyc | Bin 0 -> 17344 bytes .../__pycache__/engines.cpython-311.pyc | Bin 0 -> 23210 bytes .../__pycache__/entities.cpython-311.pyc | Bin 0 -> 6036 bytes .../__pycache__/exclusions.cpython-311.pyc | Bin 0 -> 24321 bytes .../__pycache__/fixtures.cpython-311.pyc | Bin 0 -> 51996 bytes .../__pycache__/pickleable.cpython-311.pyc | Bin 0 -> 7713 bytes .../__pycache__/profiling.cpython-311.pyc | Bin 0 -> 14292 bytes .../__pycache__/provision.cpython-311.pyc | Bin 0 -> 23230 bytes .../__pycache__/requirements.cpython-311.pyc | Bin 0 -> 85220 bytes .../__pycache__/schema.cpython-311.pyc | Bin 0 -> 9955 bytes .../testing/__pycache__/util.cpython-311.pyc | Bin 0 -> 24698 bytes .../__pycache__/warnings.cpython-311.pyc | Bin 0 -> 2283 bytes .../sqlalchemy/testing/assertions.py | 989 ++ .../sqlalchemy/testing/assertsql.py | 517 + .../sqlalchemy/testing/asyncio.py | 131 + .../sqlalchemy/testing/config.py | 389 + .../sqlalchemy/testing/engines.py | 470 + .../sqlalchemy/testing/entities.py | 117 + .../sqlalchemy/testing/exclusions.py | 435 + .../sqlalchemy/testing/fixtures.py | 1059 ++ .../sqlalchemy/testing/pickleable.py | 155 + .../sqlalchemy/testing/plugin/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 220 bytes .../__pycache__/bootstrap.cpython-311.pyc | Bin 0 -> 2241 bytes .../__pycache__/plugin_base.cpython-311.pyc | Bin 0 -> 30901 bytes .../__pycache__/pytestplugin.cpython-311.pyc | Bin 0 -> 36945 bytes .../sqlalchemy/testing/plugin/bootstrap.py | 45 + .../sqlalchemy/testing/plugin/plugin_base.py | 778 ++ .../sqlalchemy/testing/plugin/pytestplugin.py | 858 ++ .../sqlalchemy/testing/profiling.py | 327 + .../sqlalchemy/testing/provision.py | 489 + .../sqlalchemy/testing/requirements.py | 1740 ++++ .../sqlalchemy/testing/schema.py | 225 + .../sqlalchemy/testing/suite/__init__.py | 13 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 672 bytes .../__pycache__/test_cte.cpython-311.pyc | Bin 0 -> 10674 bytes .../__pycache__/test_ddl.cpython-311.pyc | Bin 0 -> 21778 bytes .../test_deprecations.cpython-311.pyc | Bin 0 -> 10026 bytes .../__pycache__/test_dialect.cpython-311.pyc | Bin 0 -> 36249 bytes .../__pycache__/test_insert.cpython-311.pyc | Bin 0 -> 23669 bytes .../test_reflection.cpython-311.pyc | Bin 0 -> 150088 bytes .../__pycache__/test_results.cpython-311.pyc | Bin 0 -> 26495 bytes .../__pycache__/test_rowcount.cpython-311.pyc | Bin 0 -> 9232 bytes .../__pycache__/test_select.cpython-311.pyc | Bin 0 -> 115642 bytes .../__pycache__/test_sequence.cpython-311.pyc | Bin 0 -> 16965 bytes .../__pycache__/test_types.cpython-311.pyc | Bin 0 -> 103393 bytes .../test_unicode_ddl.cpython-311.pyc | Bin 0 -> 9184 bytes .../test_update_delete.cpython-311.pyc | Bin 0 -> 3728 bytes .../sqlalchemy/testing/suite/test_cte.py | 206 + .../sqlalchemy/testing/suite/test_ddl.py | 383 + .../testing/suite/test_deprecations.py | 147 + .../sqlalchemy/testing/suite/test_dialect.py | 688 ++ .../sqlalchemy/testing/suite/test_insert.py | 495 + .../testing/suite/test_reflection.py | 3070 ++++++ .../sqlalchemy/testing/suite/test_results.py | 463 + .../sqlalchemy/testing/suite/test_rowcount.py | 209 + .../sqlalchemy/testing/suite/test_select.py | 1883 ++++ .../sqlalchemy/testing/suite/test_sequence.py | 312 + .../sqlalchemy/testing/suite/test_types.py | 2028 ++++ .../testing/suite/test_unicode_ddl.py | 183 + .../testing/suite/test_update_delete.py | 62 + .../site-packages/sqlalchemy/testing/util.py | 524 + .../sqlalchemy/testing/warnings.py | 52 + .venv/Lib/site-packages/sqlalchemy/types.py | 76 + .../site-packages/sqlalchemy/util/__init__.py | 158 + .../util/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 7774 bytes .../__pycache__/_collections.cpython-311.pyc | Bin 0 -> 36706 bytes .../_concurrency_py3k.cpython-311.pyc | Bin 0 -> 10122 bytes .../util/__pycache__/_has_cy.cpython-311.pyc | Bin 0 -> 1284 bytes .../_py_collections.cpython-311.pyc | Bin 0 -> 35551 bytes .../util/__pycache__/compat.cpython-311.pyc | Bin 0 -> 13103 bytes .../__pycache__/concurrency.cpython-311.pyc | Bin 0 -> 2475 bytes .../__pycache__/deprecations.cpython-311.pyc | Bin 0 -> 14970 bytes .../__pycache__/langhelpers.cpython-311.pyc | Bin 0 -> 94590 bytes .../__pycache__/preloaded.cpython-311.pyc | Bin 0 -> 6702 bytes .../util/__pycache__/queue.cpython-311.pyc | Bin 0 -> 16670 bytes .../__pycache__/tool_support.cpython-311.pyc | Bin 0 -> 9439 bytes .../__pycache__/topological.cpython-311.pyc | Bin 0 -> 4772 bytes .../util/__pycache__/typing.cpython-311.pyc | Bin 0 -> 21894 bytes .../sqlalchemy/util/_collections.py | 723 ++ .../sqlalchemy/util/_concurrency_py3k.py | 261 + .../site-packages/sqlalchemy/util/_has_cy.py | 39 + .../sqlalchemy/util/_py_collections.py | 539 ++ .../site-packages/sqlalchemy/util/compat.py | 285 + .../sqlalchemy/util/concurrency.py | 69 + .../sqlalchemy/util/deprecations.py | 404 + .../sqlalchemy/util/langhelpers.py | 2216 +++++ .../sqlalchemy/util/preloaded.py | 150 + .../site-packages/sqlalchemy/util/queue.py | 324 + .../sqlalchemy/util/tool_support.py | 198 + .../sqlalchemy/util/topological.py | 121 + .../site-packages/sqlalchemy/util/typing.py | 568 ++ .../INSTALLER | 1 + .../typing_extensions-4.5.0.dist-info/LICENSE | 254 + .../METADATA | 190 + .../typing_extensions-4.5.0.dist-info/RECORD | 7 + .../typing_extensions-4.5.0.dist-info/WHEEL | 4 + .venv/Lib/site-packages/typing_extensions.py | 2312 +++++ .venv/Lib/site-packages/werkzeug/__init__.py | 6 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 440 bytes .../__pycache__/_internal.cpython-311.pyc | Bin 0 -> 14796 bytes .../__pycache__/_reloader.cpython-311.pyc | Bin 0 -> 22679 bytes .../__pycache__/exceptions.cpython-311.pyc | Bin 0 -> 36540 bytes .../__pycache__/formparser.cpython-311.pyc | Bin 0 -> 21091 bytes .../werkzeug/__pycache__/http.cpython-311.pyc | Bin 0 -> 59093 bytes .../__pycache__/local.cpython-311.pyc | Bin 0 -> 31239 bytes .../__pycache__/security.cpython-311.pyc | Bin 0 -> 8193 bytes .../__pycache__/serving.cpython-311.pyc | Bin 0 -> 49870 bytes .../werkzeug/__pycache__/test.cpython-311.pyc | Bin 0 -> 67363 bytes .../__pycache__/testapp.cpython-311.pyc | Bin 0 -> 9210 bytes .../werkzeug/__pycache__/urls.cpython-311.pyc | Bin 0 -> 60112 bytes .../__pycache__/user_agent.cpython-311.pyc | Bin 0 -> 2337 bytes .../__pycache__/utils.cpython-311.pyc | Bin 0 -> 30276 bytes .../werkzeug/__pycache__/wsgi.cpython-311.pyc | Bin 0 -> 36742 bytes .venv/Lib/site-packages/werkzeug/_internal.py | 311 + .venv/Lib/site-packages/werkzeug/_reloader.py | 458 + .../werkzeug/datastructures/__init__.py | 34 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 2125 bytes .../__pycache__/accept.cpython-311.pyc | Bin 0 -> 15708 bytes .../__pycache__/auth.cpython-311.pyc | Bin 0 -> 23064 bytes .../__pycache__/cache_control.cpython-311.pyc | Bin 0 -> 8697 bytes .../__pycache__/csp.cpython-311.pyc | Bin 0 -> 5972 bytes .../__pycache__/etag.cpython-311.pyc | Bin 0 -> 5719 bytes .../__pycache__/file_storage.cpython-311.pyc | Bin 0 -> 8690 bytes .../__pycache__/headers.cpython-311.pyc | Bin 0 -> 27718 bytes .../__pycache__/mixins.cpython-311.pyc | Bin 0 -> 13154 bytes .../__pycache__/range.cpython-311.pyc | Bin 0 -> 8963 bytes .../__pycache__/structures.cpython-311.pyc | Bin 0 -> 53254 bytes .../werkzeug/datastructures/accept.py | 326 + .../werkzeug/datastructures/accept.pyi | 54 + .../werkzeug/datastructures/auth.py | 509 + .../werkzeug/datastructures/cache_control.py | 175 + .../werkzeug/datastructures/cache_control.pyi | 109 + .../werkzeug/datastructures/csp.py | 94 + .../werkzeug/datastructures/csp.pyi | 169 + .../werkzeug/datastructures/etag.py | 95 + .../werkzeug/datastructures/etag.pyi | 30 + .../werkzeug/datastructures/file_storage.py | 192 + .../werkzeug/datastructures/file_storage.pyi | 47 + .../werkzeug/datastructures/headers.py | 566 ++ .../werkzeug/datastructures/headers.pyi | 109 + .../werkzeug/datastructures/mixins.py | 242 + .../werkzeug/datastructures/mixins.pyi | 97 + .../werkzeug/datastructures/range.py | 180 + .../werkzeug/datastructures/range.pyi | 57 + .../werkzeug/datastructures/structures.py | 1006 ++ .../werkzeug/datastructures/structures.pyi | 208 + .../site-packages/werkzeug/debug/__init__.py | 534 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 24622 bytes .../debug/__pycache__/console.cpython-311.pyc | Bin 0 -> 13445 bytes .../debug/__pycache__/repr.cpython-311.pyc | Bin 0 -> 16181 bytes .../debug/__pycache__/tbtools.cpython-311.pyc | Bin 0 -> 17937 bytes .../site-packages/werkzeug/debug/console.py | 219 + .../Lib/site-packages/werkzeug/debug/repr.py | 283 + .../werkzeug/debug/shared/ICON_LICENSE.md | 6 + .../werkzeug/debug/shared/console.png | Bin 0 -> 507 bytes .../werkzeug/debug/shared/debugger.js | 359 + .../werkzeug/debug/shared/less.png | Bin 0 -> 191 bytes .../werkzeug/debug/shared/more.png | Bin 0 -> 200 bytes .../werkzeug/debug/shared/style.css | 150 + .../site-packages/werkzeug/debug/tbtools.py | 437 + .../Lib/site-packages/werkzeug/exceptions.py | 879 ++ .../Lib/site-packages/werkzeug/formparser.py | 548 ++ .venv/Lib/site-packages/werkzeug/http.py | 1534 +++ .venv/Lib/site-packages/werkzeug/local.py | 643 ++ .../werkzeug/middleware/__init__.py | 22 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 732 bytes .../__pycache__/dispatcher.cpython-311.pyc | Bin 0 -> 3498 bytes .../__pycache__/http_proxy.cpython-311.pyc | Bin 0 -> 10983 bytes .../__pycache__/lint.cpython-311.pyc | Bin 0 -> 20810 bytes .../__pycache__/profiler.cpython-311.pyc | Bin 0 -> 6998 bytes .../__pycache__/proxy_fix.cpython-311.pyc | Bin 0 -> 7687 bytes .../__pycache__/shared_data.cpython-311.pyc | Bin 0 -> 13790 bytes .../werkzeug/middleware/dispatcher.py | 80 + .../werkzeug/middleware/http_proxy.py | 235 + .../site-packages/werkzeug/middleware/lint.py | 420 + .../werkzeug/middleware/profiler.py | 141 + .../werkzeug/middleware/proxy_fix.py | 182 + .../werkzeug/middleware/shared_data.py | 282 + .venv/Lib/site-packages/werkzeug/py.typed | 0 .../werkzeug/routing/__init__.py | 133 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 5079 bytes .../__pycache__/converters.cpython-311.pyc | Bin 0 -> 12887 bytes .../__pycache__/exceptions.cpython-311.pyc | Bin 0 -> 8866 bytes .../routing/__pycache__/map.cpython-311.pyc | Bin 0 -> 42002 bytes .../__pycache__/matcher.cpython-311.pyc | Bin 0 -> 9056 bytes .../routing/__pycache__/rules.cpython-311.pyc | Bin 0 -> 41401 bytes .../werkzeug/routing/converters.py | 270 + .../werkzeug/routing/exceptions.py | 148 + .../Lib/site-packages/werkzeug/routing/map.py | 974 ++ .../site-packages/werkzeug/routing/matcher.py | 202 + .../site-packages/werkzeug/routing/rules.py | 913 ++ .../site-packages/werkzeug/sansio/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 210 bytes .../sansio/__pycache__/http.cpython-311.pyc | Bin 0 -> 7000 bytes .../__pycache__/multipart.cpython-311.pyc | Bin 0 -> 15161 bytes .../__pycache__/request.cpython-311.pyc | Bin 0 -> 27502 bytes .../__pycache__/response.cpython-311.pyc | Bin 0 -> 35095 bytes .../sansio/__pycache__/utils.cpython-311.pyc | Bin 0 -> 6642 bytes .../Lib/site-packages/werkzeug/sansio/http.py | 202 + .../werkzeug/sansio/multipart.py | 313 + .../site-packages/werkzeug/sansio/request.py | 659 ++ .../site-packages/werkzeug/sansio/response.py | 789 ++ .../site-packages/werkzeug/sansio/utils.py | 158 + .venv/Lib/site-packages/werkzeug/security.py | 172 + .venv/Lib/site-packages/werkzeug/serving.py | 1107 +++ .venv/Lib/site-packages/werkzeug/test.py | 1544 +++ .venv/Lib/site-packages/werkzeug/testapp.py | 181 + .venv/Lib/site-packages/werkzeug/urls.py | 1377 +++ .../Lib/site-packages/werkzeug/user_agent.py | 47 + .venv/Lib/site-packages/werkzeug/utils.py | 690 ++ .../werkzeug/wrappers/__init__.py | 3 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 375 bytes .../__pycache__/request.cpython-311.pyc | Bin 0 -> 27686 bytes .../__pycache__/response.cpython-311.pyc | Bin 0 -> 37280 bytes .../werkzeug/wrappers/request.py | 657 ++ .../werkzeug/wrappers/response.py | 835 ++ .venv/Lib/site-packages/werkzeug/wsgi.py | 847 ++ .venv/Scripts/Activate.ps1 | 472 + .venv/Scripts/activate | 69 + .venv/Scripts/activate.bat | 34 + .venv/Scripts/deactivate.bat | 22 + .venv/Scripts/flask.exe | Bin 0 -> 108420 bytes .venv/Scripts/pip.exe | Bin 0 -> 108433 bytes .venv/Scripts/pip3.11.exe | Bin 0 -> 108433 bytes .venv/Scripts/pip3.exe | Bin 0 -> 108433 bytes .venv/Scripts/python.exe | Bin 0 -> 268160 bytes .venv/Scripts/pythonw.exe | Bin 0 -> 256376 bytes .venv/pyvenv.cfg | 5 + instance/database.db | Bin 0 -> 16384 bytes 2486 files changed, 581606 insertions(+) create mode 100644 .venv/Include/site/python3.11/greenlet/greenlet.h create mode 100644 .venv/Lib/site-packages/Flask-2.3.2.dist-info/INSTALLER create mode 100644 .venv/Lib/site-packages/Flask-2.3.2.dist-info/LICENSE.rst create mode 100644 .venv/Lib/site-packages/Flask-2.3.2.dist-info/METADATA create mode 100644 .venv/Lib/site-packages/Flask-2.3.2.dist-info/RECORD create mode 100644 .venv/Lib/site-packages/Flask-2.3.2.dist-info/REQUESTED create mode 100644 .venv/Lib/site-packages/Flask-2.3.2.dist-info/WHEEL create mode 100644 .venv/Lib/site-packages/Flask-2.3.2.dist-info/entry_points.txt create mode 100644 .venv/Lib/site-packages/Flask-2.3.2.dist-info/top_level.txt create mode 100644 .venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/INSTALLER create mode 100644 .venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/LICENSE create mode 100644 .venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/METADATA create mode 100644 .venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/RECORD create mode 100644 .venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/REQUESTED create mode 100644 .venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/WHEEL create mode 100644 .venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/top_level.txt create mode 100644 .venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/INSTALLER create mode 100644 .venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/METADATA create mode 100644 .venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/RECORD create mode 100644 .venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/REQUESTED create mode 100644 .venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/WHEEL create mode 100644 .venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/licenses/LICENSE.rst create mode 100644 .venv/Lib/site-packages/Jinja2-3.1.2.dist-info/INSTALLER create mode 100644 .venv/Lib/site-packages/Jinja2-3.1.2.dist-info/LICENSE.rst create mode 100644 .venv/Lib/site-packages/Jinja2-3.1.2.dist-info/METADATA create mode 100644 .venv/Lib/site-packages/Jinja2-3.1.2.dist-info/RECORD create mode 100644 .venv/Lib/site-packages/Jinja2-3.1.2.dist-info/WHEEL create mode 100644 .venv/Lib/site-packages/Jinja2-3.1.2.dist-info/entry_points.txt create mode 100644 .venv/Lib/site-packages/Jinja2-3.1.2.dist-info/top_level.txt create mode 100644 .venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/INSTALLER create mode 100644 .venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/LICENSE.rst create mode 100644 .venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/METADATA create mode 100644 .venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/RECORD create mode 100644 .venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/WHEEL create mode 100644 .venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/top_level.txt create mode 100644 .venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/INSTALLER create mode 100644 .venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/LICENSE create mode 100644 .venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/METADATA create mode 100644 .venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/RECORD create mode 100644 .venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/REQUESTED create mode 100644 .venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/WHEEL create mode 100644 .venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/top_level.txt create mode 100644 .venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/INSTALLER create mode 100644 .venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/LICENSE.rst create mode 100644 .venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/METADATA create mode 100644 .venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/RECORD create mode 100644 .venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/WHEEL create mode 100644 .venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/top_level.txt create mode 100644 .venv/Lib/site-packages/__pycache__/typing_extensions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/_distutils_hack/__init__.py create mode 100644 .venv/Lib/site-packages/_distutils_hack/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/_distutils_hack/__pycache__/override.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/_distutils_hack/override.py create mode 100644 .venv/Lib/site-packages/blinker-1.6.2.dist-info/INSTALLER create mode 100644 .venv/Lib/site-packages/blinker-1.6.2.dist-info/LICENSE.rst create mode 100644 .venv/Lib/site-packages/blinker-1.6.2.dist-info/METADATA create mode 100644 .venv/Lib/site-packages/blinker-1.6.2.dist-info/RECORD create mode 100644 .venv/Lib/site-packages/blinker-1.6.2.dist-info/WHEEL create mode 100644 .venv/Lib/site-packages/blinker-1.6.2.dist-info/top_level.txt create mode 100644 .venv/Lib/site-packages/blinker/__init__.py create mode 100644 .venv/Lib/site-packages/blinker/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/blinker/__pycache__/_saferef.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/blinker/__pycache__/_utilities.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/blinker/__pycache__/base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/blinker/_saferef.py create mode 100644 .venv/Lib/site-packages/blinker/_utilities.py create mode 100644 .venv/Lib/site-packages/blinker/base.py create mode 100644 .venv/Lib/site-packages/blinker/py.typed create mode 100644 .venv/Lib/site-packages/click-8.1.3.dist-info/INSTALLER create mode 100644 .venv/Lib/site-packages/click-8.1.3.dist-info/LICENSE.rst create mode 100644 .venv/Lib/site-packages/click-8.1.3.dist-info/METADATA create mode 100644 .venv/Lib/site-packages/click-8.1.3.dist-info/RECORD create mode 100644 .venv/Lib/site-packages/click-8.1.3.dist-info/WHEEL create mode 100644 .venv/Lib/site-packages/click-8.1.3.dist-info/top_level.txt create mode 100644 .venv/Lib/site-packages/click/__init__.py create mode 100644 .venv/Lib/site-packages/click/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/click/__pycache__/_compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/click/__pycache__/_termui_impl.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/click/__pycache__/_textwrap.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/click/__pycache__/_winconsole.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/click/__pycache__/core.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/click/__pycache__/decorators.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/click/__pycache__/exceptions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/click/__pycache__/formatting.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/click/__pycache__/globals.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/click/__pycache__/parser.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/click/__pycache__/shell_completion.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/click/__pycache__/termui.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/click/__pycache__/testing.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/click/__pycache__/types.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/click/__pycache__/utils.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/click/_compat.py create mode 100644 .venv/Lib/site-packages/click/_termui_impl.py create mode 100644 .venv/Lib/site-packages/click/_textwrap.py create mode 100644 .venv/Lib/site-packages/click/_winconsole.py create mode 100644 .venv/Lib/site-packages/click/core.py create mode 100644 .venv/Lib/site-packages/click/decorators.py create mode 100644 .venv/Lib/site-packages/click/exceptions.py create mode 100644 .venv/Lib/site-packages/click/formatting.py create mode 100644 .venv/Lib/site-packages/click/globals.py create mode 100644 .venv/Lib/site-packages/click/parser.py create mode 100644 .venv/Lib/site-packages/click/py.typed create mode 100644 .venv/Lib/site-packages/click/shell_completion.py create mode 100644 .venv/Lib/site-packages/click/termui.py create mode 100644 .venv/Lib/site-packages/click/testing.py create mode 100644 .venv/Lib/site-packages/click/types.py create mode 100644 .venv/Lib/site-packages/click/utils.py create mode 100644 .venv/Lib/site-packages/colorama-0.4.6.dist-info/INSTALLER create mode 100644 .venv/Lib/site-packages/colorama-0.4.6.dist-info/METADATA create mode 100644 .venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD create mode 100644 .venv/Lib/site-packages/colorama-0.4.6.dist-info/WHEEL create mode 100644 .venv/Lib/site-packages/colorama-0.4.6.dist-info/licenses/LICENSE.txt create mode 100644 .venv/Lib/site-packages/colorama/__init__.py create mode 100644 .venv/Lib/site-packages/colorama/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/colorama/__pycache__/ansi.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/colorama/__pycache__/ansitowin32.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/colorama/__pycache__/initialise.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/colorama/__pycache__/win32.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/colorama/__pycache__/winterm.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/colorama/ansi.py create mode 100644 .venv/Lib/site-packages/colorama/ansitowin32.py create mode 100644 .venv/Lib/site-packages/colorama/initialise.py create mode 100644 .venv/Lib/site-packages/colorama/tests/__init__.py create mode 100644 .venv/Lib/site-packages/colorama/tests/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/colorama/tests/__pycache__/ansi_test.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/colorama/tests/__pycache__/ansitowin32_test.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/colorama/tests/__pycache__/initialise_test.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/colorama/tests/__pycache__/isatty_test.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/colorama/tests/__pycache__/utils.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/colorama/tests/__pycache__/winterm_test.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/colorama/tests/ansi_test.py create mode 100644 .venv/Lib/site-packages/colorama/tests/ansitowin32_test.py create mode 100644 .venv/Lib/site-packages/colorama/tests/initialise_test.py create mode 100644 .venv/Lib/site-packages/colorama/tests/isatty_test.py create mode 100644 .venv/Lib/site-packages/colorama/tests/utils.py create mode 100644 .venv/Lib/site-packages/colorama/tests/winterm_test.py create mode 100644 .venv/Lib/site-packages/colorama/win32.py create mode 100644 .venv/Lib/site-packages/colorama/winterm.py create mode 100644 .venv/Lib/site-packages/distutils-precedence.pth create mode 100644 .venv/Lib/site-packages/flask/__init__.py create mode 100644 .venv/Lib/site-packages/flask/__main__.py create mode 100644 .venv/Lib/site-packages/flask/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/__pycache__/__main__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/__pycache__/app.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/__pycache__/blueprints.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/__pycache__/cli.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/__pycache__/config.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/__pycache__/ctx.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/__pycache__/debughelpers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/__pycache__/globals.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/__pycache__/helpers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/__pycache__/logging.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/__pycache__/scaffold.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/__pycache__/sessions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/__pycache__/signals.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/__pycache__/templating.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/__pycache__/testing.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/__pycache__/typing.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/__pycache__/views.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/__pycache__/wrappers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/app.py create mode 100644 .venv/Lib/site-packages/flask/blueprints.py create mode 100644 .venv/Lib/site-packages/flask/cli.py create mode 100644 .venv/Lib/site-packages/flask/config.py create mode 100644 .venv/Lib/site-packages/flask/ctx.py create mode 100644 .venv/Lib/site-packages/flask/debughelpers.py create mode 100644 .venv/Lib/site-packages/flask/globals.py create mode 100644 .venv/Lib/site-packages/flask/helpers.py create mode 100644 .venv/Lib/site-packages/flask/json/__init__.py create mode 100644 .venv/Lib/site-packages/flask/json/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/json/__pycache__/provider.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/json/__pycache__/tag.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask/json/provider.py create mode 100644 .venv/Lib/site-packages/flask/json/tag.py create mode 100644 .venv/Lib/site-packages/flask/logging.py create mode 100644 .venv/Lib/site-packages/flask/py.typed create mode 100644 .venv/Lib/site-packages/flask/scaffold.py create mode 100644 .venv/Lib/site-packages/flask/sessions.py create mode 100644 .venv/Lib/site-packages/flask/signals.py create mode 100644 .venv/Lib/site-packages/flask/templating.py create mode 100644 .venv/Lib/site-packages/flask/testing.py create mode 100644 .venv/Lib/site-packages/flask/typing.py create mode 100644 .venv/Lib/site-packages/flask/views.py create mode 100644 .venv/Lib/site-packages/flask/wrappers.py create mode 100644 .venv/Lib/site-packages/flask_login/__about__.py create mode 100644 .venv/Lib/site-packages/flask_login/__init__.py create mode 100644 .venv/Lib/site-packages/flask_login/__pycache__/__about__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask_login/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask_login/__pycache__/config.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask_login/__pycache__/login_manager.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask_login/__pycache__/mixins.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask_login/__pycache__/signals.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask_login/__pycache__/test_client.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask_login/__pycache__/utils.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask_login/config.py create mode 100644 .venv/Lib/site-packages/flask_login/login_manager.py create mode 100644 .venv/Lib/site-packages/flask_login/mixins.py create mode 100644 .venv/Lib/site-packages/flask_login/signals.py create mode 100644 .venv/Lib/site-packages/flask_login/test_client.py create mode 100644 .venv/Lib/site-packages/flask_login/utils.py create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/__init__.py create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/__pycache__/cli.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/__pycache__/extension.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/__pycache__/model.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/__pycache__/pagination.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/__pycache__/query.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/__pycache__/record_queries.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/__pycache__/session.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/__pycache__/table.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/__pycache__/track_modifications.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/cli.py create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/extension.py create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/model.py create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/pagination.py create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/py.typed create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/query.py create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/record_queries.py create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/session.py create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/table.py create mode 100644 .venv/Lib/site-packages/flask_sqlalchemy/track_modifications.py create mode 100644 .venv/Lib/site-packages/greenlet-2.0.2.dist-info/AUTHORS create mode 100644 .venv/Lib/site-packages/greenlet-2.0.2.dist-info/INSTALLER create mode 100644 .venv/Lib/site-packages/greenlet-2.0.2.dist-info/LICENSE create mode 100644 .venv/Lib/site-packages/greenlet-2.0.2.dist-info/LICENSE.PSF create mode 100644 .venv/Lib/site-packages/greenlet-2.0.2.dist-info/METADATA create mode 100644 .venv/Lib/site-packages/greenlet-2.0.2.dist-info/RECORD create mode 100644 .venv/Lib/site-packages/greenlet-2.0.2.dist-info/WHEEL create mode 100644 .venv/Lib/site-packages/greenlet-2.0.2.dist-info/top_level.txt create mode 100644 .venv/Lib/site-packages/greenlet/__init__.py create mode 100644 .venv/Lib/site-packages/greenlet/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/greenlet/_greenlet.cp311-win_amd64.pyd create mode 100644 .venv/Lib/site-packages/greenlet/greenlet.cpp create mode 100644 .venv/Lib/site-packages/greenlet/greenlet.h create mode 100644 .venv/Lib/site-packages/greenlet/greenlet_allocator.hpp create mode 100644 .venv/Lib/site-packages/greenlet/greenlet_compiler_compat.hpp create mode 100644 .venv/Lib/site-packages/greenlet/greenlet_cpython_compat.hpp create mode 100644 .venv/Lib/site-packages/greenlet/greenlet_exceptions.hpp create mode 100644 .venv/Lib/site-packages/greenlet/greenlet_greenlet.hpp create mode 100644 .venv/Lib/site-packages/greenlet/greenlet_internal.hpp create mode 100644 .venv/Lib/site-packages/greenlet/greenlet_refs.hpp create mode 100644 .venv/Lib/site-packages/greenlet/greenlet_slp_switch.hpp create mode 100644 .venv/Lib/site-packages/greenlet/greenlet_thread_state.hpp create mode 100644 .venv/Lib/site-packages/greenlet/greenlet_thread_state_dict_cleanup.hpp create mode 100644 .venv/Lib/site-packages/greenlet/greenlet_thread_support.hpp create mode 100644 .venv/Lib/site-packages/greenlet/platform/__init__.py create mode 100644 .venv/Lib/site-packages/greenlet/platform/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/greenlet/platform/setup_switch_x64_masm.cmd create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_aarch64_gcc.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_alpha_unix.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_amd64_unix.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_arm32_gcc.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_arm32_ios.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_arm64_masm.asm create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_arm64_masm.obj create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_arm64_msvc.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_csky_gcc.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_m68k_gcc.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_mips_unix.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_ppc64_aix.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_ppc64_linux.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_ppc_aix.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_ppc_linux.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_ppc_macosx.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_ppc_unix.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_riscv_unix.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_s390_unix.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_sparc_sun_gcc.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_x32_unix.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_x64_masm.asm create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_x64_masm.obj create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_x64_msvc.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_x86_msvc.h create mode 100644 .venv/Lib/site-packages/greenlet/platform/switch_x86_unix.h create mode 100644 .venv/Lib/site-packages/greenlet/slp_platformselect.h create mode 100644 .venv/Lib/site-packages/greenlet/tests/__init__.py create mode 100644 .venv/Lib/site-packages/greenlet/tests/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/greenlet/tests/__pycache__/leakcheck.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/greenlet/tests/__pycache__/test_contextvars.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/greenlet/tests/__pycache__/test_cpp.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/greenlet/tests/__pycache__/test_extension_interface.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/greenlet/tests/__pycache__/test_gc.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/greenlet/tests/__pycache__/test_generator.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/greenlet/tests/__pycache__/test_generator_nested.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/greenlet/tests/__pycache__/test_greenlet.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/greenlet/tests/__pycache__/test_greenlet_trash.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/greenlet/tests/__pycache__/test_leaks.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/greenlet/tests/__pycache__/test_stack_saved.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/greenlet/tests/__pycache__/test_throw.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/greenlet/tests/__pycache__/test_tracing.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/greenlet/tests/__pycache__/test_version.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/greenlet/tests/__pycache__/test_weakref.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/greenlet/tests/_test_extension.c create mode 100644 .venv/Lib/site-packages/greenlet/tests/_test_extension.cp311-win_amd64.pyd create mode 100644 .venv/Lib/site-packages/greenlet/tests/_test_extension_cpp.cp311-win_amd64.pyd create mode 100644 .venv/Lib/site-packages/greenlet/tests/_test_extension_cpp.cpp create mode 100644 .venv/Lib/site-packages/greenlet/tests/leakcheck.py create mode 100644 .venv/Lib/site-packages/greenlet/tests/test_contextvars.py create mode 100644 .venv/Lib/site-packages/greenlet/tests/test_cpp.py create mode 100644 .venv/Lib/site-packages/greenlet/tests/test_extension_interface.py create mode 100644 .venv/Lib/site-packages/greenlet/tests/test_gc.py create mode 100644 .venv/Lib/site-packages/greenlet/tests/test_generator.py create mode 100644 .venv/Lib/site-packages/greenlet/tests/test_generator_nested.py create mode 100644 .venv/Lib/site-packages/greenlet/tests/test_greenlet.py create mode 100644 .venv/Lib/site-packages/greenlet/tests/test_greenlet_trash.py create mode 100644 .venv/Lib/site-packages/greenlet/tests/test_leaks.py create mode 100644 .venv/Lib/site-packages/greenlet/tests/test_stack_saved.py create mode 100644 .venv/Lib/site-packages/greenlet/tests/test_throw.py create mode 100644 .venv/Lib/site-packages/greenlet/tests/test_tracing.py create mode 100644 .venv/Lib/site-packages/greenlet/tests/test_version.py create mode 100644 .venv/Lib/site-packages/greenlet/tests/test_weakref.py create mode 100644 .venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/INSTALLER create mode 100644 .venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/LICENSE.rst create mode 100644 .venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/METADATA create mode 100644 .venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/RECORD create mode 100644 .venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/WHEEL create mode 100644 .venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/top_level.txt create mode 100644 .venv/Lib/site-packages/itsdangerous/__init__.py create mode 100644 .venv/Lib/site-packages/itsdangerous/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/itsdangerous/__pycache__/_json.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/itsdangerous/__pycache__/encoding.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/itsdangerous/__pycache__/exc.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/itsdangerous/__pycache__/serializer.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/itsdangerous/__pycache__/signer.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/itsdangerous/__pycache__/timed.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/itsdangerous/__pycache__/url_safe.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/itsdangerous/_json.py create mode 100644 .venv/Lib/site-packages/itsdangerous/encoding.py create mode 100644 .venv/Lib/site-packages/itsdangerous/exc.py create mode 100644 .venv/Lib/site-packages/itsdangerous/py.typed create mode 100644 .venv/Lib/site-packages/itsdangerous/serializer.py create mode 100644 .venv/Lib/site-packages/itsdangerous/signer.py create mode 100644 .venv/Lib/site-packages/itsdangerous/timed.py create mode 100644 .venv/Lib/site-packages/itsdangerous/url_safe.py create mode 100644 .venv/Lib/site-packages/jinja2/__init__.py create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/_identifier.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/async_utils.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/bccache.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/compiler.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/constants.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/debug.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/defaults.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/environment.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/exceptions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/ext.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/filters.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/idtracking.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/lexer.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/loaders.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/meta.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/nativetypes.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/nodes.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/optimizer.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/parser.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/runtime.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/sandbox.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/tests.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/utils.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/__pycache__/visitor.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/jinja2/_identifier.py create mode 100644 .venv/Lib/site-packages/jinja2/async_utils.py create mode 100644 .venv/Lib/site-packages/jinja2/bccache.py create mode 100644 .venv/Lib/site-packages/jinja2/compiler.py create mode 100644 .venv/Lib/site-packages/jinja2/constants.py create mode 100644 .venv/Lib/site-packages/jinja2/debug.py create mode 100644 .venv/Lib/site-packages/jinja2/defaults.py create mode 100644 .venv/Lib/site-packages/jinja2/environment.py create mode 100644 .venv/Lib/site-packages/jinja2/exceptions.py create mode 100644 .venv/Lib/site-packages/jinja2/ext.py create mode 100644 .venv/Lib/site-packages/jinja2/filters.py create mode 100644 .venv/Lib/site-packages/jinja2/idtracking.py create mode 100644 .venv/Lib/site-packages/jinja2/lexer.py create mode 100644 .venv/Lib/site-packages/jinja2/loaders.py create mode 100644 .venv/Lib/site-packages/jinja2/meta.py create mode 100644 .venv/Lib/site-packages/jinja2/nativetypes.py create mode 100644 .venv/Lib/site-packages/jinja2/nodes.py create mode 100644 .venv/Lib/site-packages/jinja2/optimizer.py create mode 100644 .venv/Lib/site-packages/jinja2/parser.py create mode 100644 .venv/Lib/site-packages/jinja2/py.typed create mode 100644 .venv/Lib/site-packages/jinja2/runtime.py create mode 100644 .venv/Lib/site-packages/jinja2/sandbox.py create mode 100644 .venv/Lib/site-packages/jinja2/tests.py create mode 100644 .venv/Lib/site-packages/jinja2/utils.py create mode 100644 .venv/Lib/site-packages/jinja2/visitor.py create mode 100644 .venv/Lib/site-packages/markupsafe/__init__.py create mode 100644 .venv/Lib/site-packages/markupsafe/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/markupsafe/__pycache__/_native.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/markupsafe/_native.py create mode 100644 .venv/Lib/site-packages/markupsafe/_speedups.c create mode 100644 .venv/Lib/site-packages/markupsafe/_speedups.cp311-win_amd64.pyd create mode 100644 .venv/Lib/site-packages/markupsafe/_speedups.pyi create mode 100644 .venv/Lib/site-packages/markupsafe/py.typed create mode 100644 .venv/Lib/site-packages/pip-22.3.1.dist-info/INSTALLER create mode 100644 .venv/Lib/site-packages/pip-22.3.1.dist-info/LICENSE.txt create mode 100644 .venv/Lib/site-packages/pip-22.3.1.dist-info/METADATA create mode 100644 .venv/Lib/site-packages/pip-22.3.1.dist-info/RECORD create mode 100644 .venv/Lib/site-packages/pip-22.3.1.dist-info/REQUESTED create mode 100644 .venv/Lib/site-packages/pip-22.3.1.dist-info/WHEEL create mode 100644 .venv/Lib/site-packages/pip-22.3.1.dist-info/entry_points.txt create mode 100644 .venv/Lib/site-packages/pip-22.3.1.dist-info/top_level.txt create mode 100644 .venv/Lib/site-packages/pip/__init__.py create mode 100644 .venv/Lib/site-packages/pip/__main__.py create mode 100644 .venv/Lib/site-packages/pip/__pip-runner__.py create mode 100644 .venv/Lib/site-packages/pip/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/__pycache__/__main__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/__pycache__/__pip-runner__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/__pycache__/build_env.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/__pycache__/cache.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/__pycache__/configuration.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/__pycache__/exceptions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/__pycache__/main.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/__pycache__/pyproject.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/build_env.py create mode 100644 .venv/Lib/site-packages/pip/_internal/cache.py create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/__pycache__/main.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/__pycache__/parser.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/__pycache__/progress_bars.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/autocompletion.py create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/base_command.py create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/cmdoptions.py create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/command_context.py create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/main.py create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/main_parser.py create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/parser.py create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/progress_bars.py create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/req_command.py create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/spinners.py create mode 100644 .venv/Lib/site-packages/pip/_internal/cli/status_codes.py create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__pycache__/cache.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__pycache__/check.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__pycache__/completion.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__pycache__/debug.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__pycache__/download.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__pycache__/hash.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__pycache__/help.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__pycache__/index.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__pycache__/install.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__pycache__/list.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__pycache__/search.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__pycache__/show.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/cache.py create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/check.py create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/completion.py create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/configuration.py create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/debug.py create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/download.py create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/freeze.py create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/hash.py create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/help.py create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/index.py create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/inspect.py create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/install.py create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/list.py create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/search.py create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/show.py create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/uninstall.py create mode 100644 .venv/Lib/site-packages/pip/_internal/commands/wheel.py create mode 100644 .venv/Lib/site-packages/pip/_internal/configuration.py create mode 100644 .venv/Lib/site-packages/pip/_internal/distributions/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/distributions/__pycache__/base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/distributions/base.py create mode 100644 .venv/Lib/site-packages/pip/_internal/distributions/installed.py create mode 100644 .venv/Lib/site-packages/pip/_internal/distributions/sdist.py create mode 100644 .venv/Lib/site-packages/pip/_internal/distributions/wheel.py create mode 100644 .venv/Lib/site-packages/pip/_internal/exceptions.py create mode 100644 .venv/Lib/site-packages/pip/_internal/index/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/index/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/index/__pycache__/collector.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/index/__pycache__/package_finder.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/index/__pycache__/sources.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/index/collector.py create mode 100644 .venv/Lib/site-packages/pip/_internal/index/package_finder.py create mode 100644 .venv/Lib/site-packages/pip/_internal/index/sources.py create mode 100644 .venv/Lib/site-packages/pip/_internal/locations/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/locations/__pycache__/base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/locations/_distutils.py create mode 100644 .venv/Lib/site-packages/pip/_internal/locations/_sysconfig.py create mode 100644 .venv/Lib/site-packages/pip/_internal/locations/base.py create mode 100644 .venv/Lib/site-packages/pip/_internal/main.py create mode 100644 .venv/Lib/site-packages/pip/_internal/metadata/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/metadata/__pycache__/_json.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/metadata/__pycache__/base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/metadata/_json.py create mode 100644 .venv/Lib/site-packages/pip/_internal/metadata/base.py create mode 100644 .venv/Lib/site-packages/pip/_internal/metadata/importlib/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_dists.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_envs.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/metadata/importlib/_compat.py create mode 100644 .venv/Lib/site-packages/pip/_internal/metadata/importlib/_dists.py create mode 100644 .venv/Lib/site-packages/pip/_internal/metadata/importlib/_envs.py create mode 100644 .venv/Lib/site-packages/pip/_internal/metadata/pkg_resources.py create mode 100644 .venv/Lib/site-packages/pip/_internal/models/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/models/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/models/__pycache__/candidate.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/models/__pycache__/format_control.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/models/__pycache__/index.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/models/__pycache__/link.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/models/__pycache__/scheme.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/models/__pycache__/target_python.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/models/__pycache__/wheel.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/models/candidate.py create mode 100644 .venv/Lib/site-packages/pip/_internal/models/direct_url.py create mode 100644 .venv/Lib/site-packages/pip/_internal/models/format_control.py create mode 100644 .venv/Lib/site-packages/pip/_internal/models/index.py create mode 100644 .venv/Lib/site-packages/pip/_internal/models/installation_report.py create mode 100644 .venv/Lib/site-packages/pip/_internal/models/link.py create mode 100644 .venv/Lib/site-packages/pip/_internal/models/scheme.py create mode 100644 .venv/Lib/site-packages/pip/_internal/models/search_scope.py create mode 100644 .venv/Lib/site-packages/pip/_internal/models/selection_prefs.py create mode 100644 .venv/Lib/site-packages/pip/_internal/models/target_python.py create mode 100644 .venv/Lib/site-packages/pip/_internal/models/wheel.py create mode 100644 .venv/Lib/site-packages/pip/_internal/network/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/network/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/network/__pycache__/auth.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/network/__pycache__/cache.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/network/__pycache__/download.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/network/__pycache__/session.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/network/__pycache__/utils.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/network/auth.py create mode 100644 .venv/Lib/site-packages/pip/_internal/network/cache.py create mode 100644 .venv/Lib/site-packages/pip/_internal/network/download.py create mode 100644 .venv/Lib/site-packages/pip/_internal/network/lazy_wheel.py create mode 100644 .venv/Lib/site-packages/pip/_internal/network/session.py create mode 100644 .venv/Lib/site-packages/pip/_internal/network/utils.py create mode 100644 .venv/Lib/site-packages/pip/_internal/network/xmlrpc.py create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/__pycache__/check.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/build/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/build/build_tracker.py create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/build/metadata.py create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/build/metadata_editable.py create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/build/metadata_legacy.py create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/build/wheel.py create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/build/wheel_editable.py create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/build/wheel_legacy.py create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/check.py create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/freeze.py create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/install/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/legacy.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/install/editable_legacy.py create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/install/legacy.py create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/install/wheel.py create mode 100644 .venv/Lib/site-packages/pip/_internal/operations/prepare.py create mode 100644 .venv/Lib/site-packages/pip/_internal/pyproject.py create mode 100644 .venv/Lib/site-packages/pip/_internal/req/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/req/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/req/__pycache__/constructors.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/req/__pycache__/req_file.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/req/__pycache__/req_install.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/req/__pycache__/req_set.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/req/constructors.py create mode 100644 .venv/Lib/site-packages/pip/_internal/req/req_file.py create mode 100644 .venv/Lib/site-packages/pip/_internal/req/req_install.py create mode 100644 .venv/Lib/site-packages/pip/_internal/req/req_set.py create mode 100644 .venv/Lib/site-packages/pip/_internal/req/req_uninstall.py create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/__pycache__/base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/base.py create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/legacy/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/legacy/resolver.py create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/resolvelib/base.py create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/resolvelib/candidates.py create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/resolvelib/factory.py create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/resolvelib/provider.py create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/resolvelib/reporter.py create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/resolvelib/requirements.py create mode 100644 .venv/Lib/site-packages/pip/_internal/resolution/resolvelib/resolver.py create mode 100644 .venv/Lib/site-packages/pip/_internal/self_outdated_check.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/_log.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/distutils_args.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/egg_link.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/inject_securetransport.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/logging.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/misc.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/models.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/unpacking.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/urls.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/_log.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/appdirs.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/compat.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/compatibility_tags.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/datetime.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/deprecation.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/direct_url_helpers.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/distutils_args.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/egg_link.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/encoding.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/entrypoints.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/filesystem.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/filetypes.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/glibc.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/hashes.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/inject_securetransport.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/logging.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/misc.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/models.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/packaging.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/setuptools_build.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/subprocess.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/temp_dir.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/unpacking.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/urls.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/virtualenv.py create mode 100644 .venv/Lib/site-packages/pip/_internal/utils/wheel.py create mode 100644 .venv/Lib/site-packages/pip/_internal/vcs/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/vcs/__pycache__/git.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_internal/vcs/bazaar.py create mode 100644 .venv/Lib/site-packages/pip/_internal/vcs/git.py create mode 100644 .venv/Lib/site-packages/pip/_internal/vcs/mercurial.py create mode 100644 .venv/Lib/site-packages/pip/_internal/vcs/subversion.py create mode 100644 .venv/Lib/site-packages/pip/_internal/vcs/versioncontrol.py create mode 100644 .venv/Lib/site-packages/pip/_internal/wheel_builder.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/__pycache__/six.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/_cmd.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/adapter.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/cache.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/compat.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/controller.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/filewrapper.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/heuristics.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/serialize.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/cachecontrol/wrapper.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/certifi/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/certifi/__main__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/certifi/cacert.pem create mode 100644 .venv/Lib/site-packages/pip/_vendor/certifi/core.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/big5freq.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/big5prober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/chardistribution.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/charsetgroupprober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/charsetprober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/cp949prober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/enums.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/escprober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/escsm.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/eucjpprober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euckrfreq.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euckrprober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euctwfreq.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euctwprober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/gb2312freq.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/gb2312prober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/hebrewprober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/jisfreq.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/johabfreq.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/johabprober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/jpcntx.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langgreekmodel.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langhebrewmodel.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langhungarianmodel.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langrussianmodel.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langthaimodel.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langturkishmodel.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/latin1prober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/mbcssm.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/sbcharsetprober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/sbcsgroupprober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/sjisprober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/universaldetector.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/utf1632prober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/utf8prober.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/version.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/big5freq.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/big5prober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/chardistribution.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/charsetgroupprober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/charsetprober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/cli/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/cli/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/cli/chardetect.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/codingstatemachine.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/cp949prober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/enums.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/escprober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/escsm.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/eucjpprober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/euckrfreq.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/euckrprober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/euctwfreq.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/euctwprober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/gb2312freq.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/gb2312prober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/hebrewprober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/jisfreq.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/johabfreq.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/johabprober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/jpcntx.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/langbulgarianmodel.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/langgreekmodel.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/langhebrewmodel.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/langhungarianmodel.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/langrussianmodel.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/langthaimodel.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/langturkishmodel.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/latin1prober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/mbcharsetprober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/mbcsgroupprober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/mbcssm.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/metadata/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/metadata/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/metadata/__pycache__/languages.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/metadata/languages.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/sbcharsetprober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/sbcsgroupprober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/sjisprober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/universaldetector.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/utf1632prober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/utf8prober.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/chardet/version.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/colorama/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/ansi.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/ansitowin32.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/initialise.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/win32.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/winterm.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/colorama/ansi.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/colorama/ansitowin32.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/colorama/initialise.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/colorama/win32.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/colorama/winterm.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/compat.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/database.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/index.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/locators.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/manifest.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/markers.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/metadata.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/resources.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/scripts.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/t32.exe create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/t64-arm.exe create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/t64.exe create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/util.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/version.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/w32.exe create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/w64-arm.exe create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/w64.exe create mode 100644 .venv/Lib/site-packages/pip/_vendor/distlib/wheel.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/distro/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/distro/__main__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/distro/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/distro/__pycache__/__main__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/distro/__pycache__/distro.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/distro/distro.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/idna/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/idna/__pycache__/core.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/idna/codec.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/idna/compat.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/idna/core.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/idna/idnadata.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/idna/intranges.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/idna/package_data.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/idna/uts46data.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/msgpack/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/msgpack/exceptions.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/msgpack/ext.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/msgpack/fallback.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/__about__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/__about__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/_manylinux.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/_musllinux.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/_structures.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/markers.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/requirements.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/specifiers.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/tags.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/utils.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/packaging/version.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/__pycache__/_compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/__pycache__/build.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/__pycache__/check.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/__pycache__/colorlog.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/__pycache__/dirtools.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/__pycache__/envbuild.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/__pycache__/meta.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/__pycache__/wrappers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/_compat.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/build.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/check.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/colorlog.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/dirtools.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/envbuild.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/in_process/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/in_process/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/in_process/__pycache__/_in_process.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/in_process/_in_process.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/meta.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pep517/wrappers.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pkg_resources/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pkg_resources/__pycache__/py31compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pkg_resources/py31compat.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/platformdirs/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/platformdirs/__main__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/macos.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/windows.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/platformdirs/android.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/platformdirs/api.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/platformdirs/macos.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/platformdirs/unix.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/platformdirs/version.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/platformdirs/windows.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/__main__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/__main__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/console.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/filter.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/formatter.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/lexer.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/modeline.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/regexopt.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/scanner.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/sphinxext.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/style.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/token.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/unistring.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/cmdline.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/console.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/filter.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/filters/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/filters/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatter.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/groff.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/img.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/irc.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/latex.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/other.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/svg.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/_mapping.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/bbcode.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/groff.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/html.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/img.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/irc.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/latex.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/other.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/pangomarkup.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/rtf.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/svg.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/terminal.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/formatters/terminal256.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/lexer.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/lexers/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/lexers/__pycache__/python.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/lexers/_mapping.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/lexers/python.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/modeline.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/plugin.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/regexopt.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/scanner.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/sphinxext.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/style.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/styles/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/styles/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/token.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/unistring.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pygments/util.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/actions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/common.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/core.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/exceptions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/helpers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/results.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/testing.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/unicode.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/actions.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/common.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/core.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/diagram/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/exceptions.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/helpers.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/results.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/testing.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/unicode.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/pyparsing/util.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__pycache__/api.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__pycache__/help.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__pycache__/models.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/__version__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/_internal_utils.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/adapters.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/api.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/auth.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/certs.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/compat.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/cookies.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/exceptions.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/help.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/hooks.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/models.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/packages.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/sessions.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/status_codes.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/structures.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/requests/utils.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/resolvelib/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/providers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/reporters.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/structs.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/resolvelib/compat/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/resolvelib/providers.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/resolvelib/reporters.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/resolvelib/resolvers.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/resolvelib/structs.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__main__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/__main__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_cell_widths.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_emoji_replace.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_export_format.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_extension.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_inspect.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_log_render.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_loop.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_palettes.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_pick.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_ratio.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_spinners.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_stack.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_timer.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_win32_console.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_windows.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_windows_renderer.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_wrap.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/abc.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/align.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/ansi.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/bar.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/box.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/cells.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/color.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/color_triplet.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/columns.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/console.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/constrain.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/containers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/control.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/default_styles.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/diagnose.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/emoji.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/errors.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/file_proxy.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/filesize.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/highlighter.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/json.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/jupyter.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/layout.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/live.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/live_render.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/logging.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/markup.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/measure.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/padding.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/pager.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/palette.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/panel.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/pretty.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/progress.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/progress_bar.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/prompt.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/protocol.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/region.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/repr.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/rule.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/scope.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/screen.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/segment.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/spinner.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/status.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/style.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/styled.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/syntax.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/table.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/terminal_theme.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/text.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/theme.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/themes.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/traceback.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/__pycache__/tree.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/_cell_widths.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/_emoji_codes.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/_emoji_replace.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/_export_format.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/_extension.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/_inspect.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/_log_render.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/_loop.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/_palettes.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/_pick.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/_ratio.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/_spinners.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/_stack.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/_timer.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/_win32_console.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/_windows.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/_windows_renderer.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/_wrap.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/abc.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/align.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/ansi.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/bar.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/box.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/cells.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/color.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/color_triplet.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/columns.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/console.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/constrain.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/containers.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/control.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/default_styles.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/diagnose.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/emoji.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/errors.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/file_proxy.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/filesize.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/highlighter.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/json.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/jupyter.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/layout.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/live.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/live_render.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/logging.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/markup.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/measure.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/padding.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/pager.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/palette.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/panel.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/pretty.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/progress.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/progress_bar.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/prompt.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/protocol.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/region.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/repr.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/rule.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/scope.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/screen.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/segment.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/spinner.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/status.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/style.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/styled.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/syntax.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/table.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/terminal_theme.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/text.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/theme.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/themes.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/traceback.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/rich/tree.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/six.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/_asyncio.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/_utils.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/after.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/before.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/before_sleep.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/nap.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/retry.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/stop.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/tornadoweb.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/wait.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/_asyncio.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/_utils.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/after.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/before.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/before_sleep.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/nap.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/retry.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/stop.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/tornadoweb.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/tenacity/wait.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/tomli/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_types.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/tomli/_parser.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/tomli/_re.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/tomli/_types.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/typing_extensions.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/_collections.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/_version.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/connection.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/connectionpool.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/appengine.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/securetransport.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/contrib/socks.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/exceptions.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/fields.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/filepost.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/packages/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/packages/six.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/poolmanager.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/request.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/response.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/connection.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/proxy.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/queue.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/request.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/response.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/retry.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/ssl_.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/ssl_match_hostname.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/ssltransport.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/timeout.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/url.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/urllib3/util/wait.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/vendor.txt create mode 100644 .venv/Lib/site-packages/pip/_vendor/webencodings/__init__.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/labels.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/mklabels.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/tests.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pip/_vendor/webencodings/labels.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/webencodings/mklabels.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/webencodings/tests.py create mode 100644 .venv/Lib/site-packages/pip/_vendor/webencodings/x_user_defined.py create mode 100644 .venv/Lib/site-packages/pip/py.typed create mode 100644 .venv/Lib/site-packages/pkg_resources/__init__.py create mode 100644 .venv/Lib/site-packages/pkg_resources/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/__init__.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/__pycache__/appdirs.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/__pycache__/zipp.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/appdirs.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/__init__.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/__pycache__/_adapters.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/__pycache__/_common.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/__pycache__/_compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/__pycache__/_itertools.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/__pycache__/_legacy.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/__pycache__/abc.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/__pycache__/readers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/__pycache__/simple.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/_adapters.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/_common.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/_compat.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/_itertools.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/_legacy.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/abc.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/readers.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/simple.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/jaraco/__init__.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/jaraco/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/jaraco/__pycache__/context.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/jaraco/__pycache__/functools.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/jaraco/context.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/jaraco/functools.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/jaraco/text/__init__.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/jaraco/text/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/more_itertools/__init__.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/more_itertools/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/more_itertools/__pycache__/more.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/more_itertools/__pycache__/recipes.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/more_itertools/more.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/more_itertools/recipes.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/__about__.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/__init__.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/__about__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/_manylinux.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/_musllinux.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/_structures.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/markers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/requirements.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/specifiers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/tags.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/utils.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/version.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/_manylinux.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/_musllinux.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/_structures.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/markers.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/requirements.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/specifiers.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/tags.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/utils.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/packaging/version.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/__init__.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/actions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/common.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/core.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/exceptions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/helpers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/results.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/testing.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/unicode.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/actions.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/common.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/core.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/diagram/__init__.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/exceptions.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/helpers.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/results.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/testing.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/unicode.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/util.py create mode 100644 .venv/Lib/site-packages/pkg_resources/_vendor/zipp.py create mode 100644 .venv/Lib/site-packages/pkg_resources/extern/__init__.py create mode 100644 .venv/Lib/site-packages/pkg_resources/extern/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools-65.5.0.dist-info/INSTALLER create mode 100644 .venv/Lib/site-packages/setuptools-65.5.0.dist-info/LICENSE create mode 100644 .venv/Lib/site-packages/setuptools-65.5.0.dist-info/METADATA create mode 100644 .venv/Lib/site-packages/setuptools-65.5.0.dist-info/RECORD create mode 100644 .venv/Lib/site-packages/setuptools-65.5.0.dist-info/REQUESTED create mode 100644 .venv/Lib/site-packages/setuptools-65.5.0.dist-info/WHEEL create mode 100644 .venv/Lib/site-packages/setuptools-65.5.0.dist-info/entry_points.txt create mode 100644 .venv/Lib/site-packages/setuptools-65.5.0.dist-info/top_level.txt create mode 100644 .venv/Lib/site-packages/setuptools/__init__.py create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/_deprecation_warning.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/_entry_points.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/_imp.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/_importlib.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/_itertools.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/_path.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/_reqs.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/archive_util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/build_meta.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/dep_util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/depends.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/discovery.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/dist.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/errors.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/extension.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/glob.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/installer.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/launch.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/logging.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/monkey.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/msvc.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/namespaces.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/package_index.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/py34compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/sandbox.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/unicode_utils.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/version.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/wheel.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/__pycache__/windows_support.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_deprecation_warning.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__init__.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/_collections.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/_functools.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/_macos_compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/_msvccompiler.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/archive_util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/bcppcompiler.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/ccompiler.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/cmd.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/config.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/core.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/cygwinccompiler.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/debug.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/dep_util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/dir_util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/dist.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/errors.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/extension.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/fancy_getopt.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/file_util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/filelist.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/log.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/msvc9compiler.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/msvccompiler.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/py38compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/py39compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/spawn.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/sysconfig.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/text_file.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/unixccompiler.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/version.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/__pycache__/versionpredicate.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/_collections.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/_functools.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/_macos_compat.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/_msvccompiler.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/archive_util.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/bcppcompiler.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/ccompiler.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/cmd.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__init__.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/_framework_compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist_dumb.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist_rpm.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/build.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_clib.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_ext.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_py.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_scripts.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/check.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/clean.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/config.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/install.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_data.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_egg_info.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_headers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_lib.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_scripts.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/py37compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/register.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/sdist.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/__pycache__/upload.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/_framework_compat.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/bdist.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/bdist_dumb.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/bdist_rpm.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/build.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/build_clib.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/build_ext.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/build_py.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/build_scripts.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/check.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/clean.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/config.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/install.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/install_data.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/install_egg_info.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/install_headers.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/install_lib.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/install_scripts.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/py37compat.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/register.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/sdist.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/command/upload.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/config.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/core.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/cygwinccompiler.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/debug.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/dep_util.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/dir_util.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/dist.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/errors.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/extension.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/fancy_getopt.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/file_util.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/filelist.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/log.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/msvc9compiler.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/msvccompiler.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/py38compat.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/py39compat.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/spawn.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/sysconfig.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/text_file.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/unixccompiler.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/util.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/version.py create mode 100644 .venv/Lib/site-packages/setuptools/_distutils/versionpredicate.py create mode 100644 .venv/Lib/site-packages/setuptools/_entry_points.py create mode 100644 .venv/Lib/site-packages/setuptools/_imp.py create mode 100644 .venv/Lib/site-packages/setuptools/_importlib.py create mode 100644 .venv/Lib/site-packages/setuptools/_itertools.py create mode 100644 .venv/Lib/site-packages/setuptools/_path.py create mode 100644 .venv/Lib/site-packages/setuptools/_reqs.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/__init__.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/__pycache__/ordered_set.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/__pycache__/typing_extensions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/__pycache__/zipp.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/__init__.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/__pycache__/_adapters.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/__pycache__/_collections.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/__pycache__/_compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/__pycache__/_functools.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/__pycache__/_itertools.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/__pycache__/_meta.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/__pycache__/_text.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/_adapters.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/_collections.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/_compat.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/_functools.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/_itertools.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/_meta.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/_text.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_resources/__init__.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_resources/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_resources/__pycache__/_adapters.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_resources/__pycache__/_common.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_resources/__pycache__/_compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_resources/__pycache__/_itertools.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_resources/__pycache__/_legacy.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_resources/__pycache__/abc.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_resources/__pycache__/readers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_resources/__pycache__/simple.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_resources/_adapters.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_resources/_common.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_resources/_compat.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_resources/_itertools.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_resources/_legacy.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_resources/abc.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_resources/readers.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/importlib_resources/simple.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/jaraco/__init__.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/jaraco/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/jaraco/__pycache__/context.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/jaraco/__pycache__/functools.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/jaraco/context.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/jaraco/functools.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/jaraco/text/__init__.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/jaraco/text/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/more_itertools/__init__.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/more_itertools/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/more_itertools/__pycache__/more.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/more_itertools/__pycache__/recipes.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/more_itertools/more.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/more_itertools/recipes.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/ordered_set.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/__about__.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/__init__.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/__about__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/_manylinux.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/_musllinux.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/_structures.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/markers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/requirements.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/specifiers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/tags.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/utils.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/version.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/_manylinux.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/_musllinux.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/_structures.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/markers.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/requirements.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/specifiers.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/tags.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/utils.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/packaging/version.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/__init__.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/__pycache__/actions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/__pycache__/common.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/__pycache__/core.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/__pycache__/exceptions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/__pycache__/helpers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/__pycache__/results.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/__pycache__/testing.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/__pycache__/unicode.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/__pycache__/util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/actions.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/common.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/core.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/diagram/__init__.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/exceptions.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/helpers.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/results.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/testing.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/unicode.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/pyparsing/util.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/tomli/__init__.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/tomli/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/tomli/__pycache__/_parser.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/tomli/__pycache__/_re.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/tomli/__pycache__/_types.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/tomli/_parser.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/tomli/_re.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/tomli/_types.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/typing_extensions.py create mode 100644 .venv/Lib/site-packages/setuptools/_vendor/zipp.py create mode 100644 .venv/Lib/site-packages/setuptools/archive_util.py create mode 100644 .venv/Lib/site-packages/setuptools/build_meta.py create mode 100644 .venv/Lib/site-packages/setuptools/cli-32.exe create mode 100644 .venv/Lib/site-packages/setuptools/cli-64.exe create mode 100644 .venv/Lib/site-packages/setuptools/cli-arm64.exe create mode 100644 .venv/Lib/site-packages/setuptools/cli.exe create mode 100644 .venv/Lib/site-packages/setuptools/command/__init__.py create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/alias.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/bdist_egg.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/bdist_rpm.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/build.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/build_clib.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/build_ext.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/build_py.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/develop.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/dist_info.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/easy_install.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/editable_wheel.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/egg_info.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/install.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/install_egg_info.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/install_lib.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/install_scripts.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/py36compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/register.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/rotate.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/saveopts.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/sdist.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/setopt.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/test.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/upload.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/__pycache__/upload_docs.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/command/alias.py create mode 100644 .venv/Lib/site-packages/setuptools/command/bdist_egg.py create mode 100644 .venv/Lib/site-packages/setuptools/command/bdist_rpm.py create mode 100644 .venv/Lib/site-packages/setuptools/command/build.py create mode 100644 .venv/Lib/site-packages/setuptools/command/build_clib.py create mode 100644 .venv/Lib/site-packages/setuptools/command/build_ext.py create mode 100644 .venv/Lib/site-packages/setuptools/command/build_py.py create mode 100644 .venv/Lib/site-packages/setuptools/command/develop.py create mode 100644 .venv/Lib/site-packages/setuptools/command/dist_info.py create mode 100644 .venv/Lib/site-packages/setuptools/command/easy_install.py create mode 100644 .venv/Lib/site-packages/setuptools/command/editable_wheel.py create mode 100644 .venv/Lib/site-packages/setuptools/command/egg_info.py create mode 100644 .venv/Lib/site-packages/setuptools/command/install.py create mode 100644 .venv/Lib/site-packages/setuptools/command/install_egg_info.py create mode 100644 .venv/Lib/site-packages/setuptools/command/install_lib.py create mode 100644 .venv/Lib/site-packages/setuptools/command/install_scripts.py create mode 100644 .venv/Lib/site-packages/setuptools/command/launcher manifest.xml create mode 100644 .venv/Lib/site-packages/setuptools/command/py36compat.py create mode 100644 .venv/Lib/site-packages/setuptools/command/register.py create mode 100644 .venv/Lib/site-packages/setuptools/command/rotate.py create mode 100644 .venv/Lib/site-packages/setuptools/command/saveopts.py create mode 100644 .venv/Lib/site-packages/setuptools/command/sdist.py create mode 100644 .venv/Lib/site-packages/setuptools/command/setopt.py create mode 100644 .venv/Lib/site-packages/setuptools/command/test.py create mode 100644 .venv/Lib/site-packages/setuptools/command/upload.py create mode 100644 .venv/Lib/site-packages/setuptools/command/upload_docs.py create mode 100644 .venv/Lib/site-packages/setuptools/config/__init__.py create mode 100644 .venv/Lib/site-packages/setuptools/config/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/config/__pycache__/_apply_pyprojecttoml.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/config/__pycache__/expand.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/config/__pycache__/pyprojecttoml.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/config/__pycache__/setupcfg.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/config/_apply_pyprojecttoml.py create mode 100644 .venv/Lib/site-packages/setuptools/config/_validate_pyproject/__init__.py create mode 100644 .venv/Lib/site-packages/setuptools/config/_validate_pyproject/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/config/_validate_pyproject/__pycache__/error_reporting.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/config/_validate_pyproject/__pycache__/extra_validations.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/config/_validate_pyproject/__pycache__/fastjsonschema_exceptions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/config/_validate_pyproject/__pycache__/fastjsonschema_validations.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/config/_validate_pyproject/__pycache__/formats.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/config/_validate_pyproject/error_reporting.py create mode 100644 .venv/Lib/site-packages/setuptools/config/_validate_pyproject/extra_validations.py create mode 100644 .venv/Lib/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_exceptions.py create mode 100644 .venv/Lib/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_validations.py create mode 100644 .venv/Lib/site-packages/setuptools/config/_validate_pyproject/formats.py create mode 100644 .venv/Lib/site-packages/setuptools/config/expand.py create mode 100644 .venv/Lib/site-packages/setuptools/config/pyprojecttoml.py create mode 100644 .venv/Lib/site-packages/setuptools/config/setupcfg.py create mode 100644 .venv/Lib/site-packages/setuptools/dep_util.py create mode 100644 .venv/Lib/site-packages/setuptools/depends.py create mode 100644 .venv/Lib/site-packages/setuptools/discovery.py create mode 100644 .venv/Lib/site-packages/setuptools/dist.py create mode 100644 .venv/Lib/site-packages/setuptools/errors.py create mode 100644 .venv/Lib/site-packages/setuptools/extension.py create mode 100644 .venv/Lib/site-packages/setuptools/extern/__init__.py create mode 100644 .venv/Lib/site-packages/setuptools/extern/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/setuptools/glob.py create mode 100644 .venv/Lib/site-packages/setuptools/gui-32.exe create mode 100644 .venv/Lib/site-packages/setuptools/gui-64.exe create mode 100644 .venv/Lib/site-packages/setuptools/gui-arm64.exe create mode 100644 .venv/Lib/site-packages/setuptools/gui.exe create mode 100644 .venv/Lib/site-packages/setuptools/installer.py create mode 100644 .venv/Lib/site-packages/setuptools/launch.py create mode 100644 .venv/Lib/site-packages/setuptools/logging.py create mode 100644 .venv/Lib/site-packages/setuptools/monkey.py create mode 100644 .venv/Lib/site-packages/setuptools/msvc.py create mode 100644 .venv/Lib/site-packages/setuptools/namespaces.py create mode 100644 .venv/Lib/site-packages/setuptools/package_index.py create mode 100644 .venv/Lib/site-packages/setuptools/py34compat.py create mode 100644 .venv/Lib/site-packages/setuptools/sandbox.py create mode 100644 .venv/Lib/site-packages/setuptools/script (dev).tmpl create mode 100644 .venv/Lib/site-packages/setuptools/script.tmpl create mode 100644 .venv/Lib/site-packages/setuptools/unicode_utils.py create mode 100644 .venv/Lib/site-packages/setuptools/version.py create mode 100644 .venv/Lib/site-packages/setuptools/wheel.py create mode 100644 .venv/Lib/site-packages/setuptools/windows_support.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/__pycache__/events.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/__pycache__/exc.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/__pycache__/inspection.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/__pycache__/log.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/__pycache__/schema.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/__pycache__/types.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/connectors/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/pyodbc.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/connectors/pyodbc.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/cyextension/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/cyextension/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/cyextension/collections.cp311-win_amd64.pyd create mode 100644 .venv/Lib/site-packages/sqlalchemy/cyextension/collections.pyx create mode 100644 .venv/Lib/site-packages/sqlalchemy/cyextension/immutabledict.cp311-win_amd64.pyd create mode 100644 .venv/Lib/site-packages/sqlalchemy/cyextension/immutabledict.pxd create mode 100644 .venv/Lib/site-packages/sqlalchemy/cyextension/immutabledict.pyx create mode 100644 .venv/Lib/site-packages/sqlalchemy/cyextension/processors.cp311-win_amd64.pyd create mode 100644 .venv/Lib/site-packages/sqlalchemy/cyextension/processors.pyx create mode 100644 .venv/Lib/site-packages/sqlalchemy/cyextension/resultproxy.cp311-win_amd64.pyd create mode 100644 .venv/Lib/site-packages/sqlalchemy/cyextension/resultproxy.pyx create mode 100644 .venv/Lib/site-packages/sqlalchemy/cyextension/util.cp311-win_amd64.pyd create mode 100644 .venv/Lib/site-packages/sqlalchemy/cyextension/util.pyx create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mssql/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/json.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/provision.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mssql/base.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mssql/information_schema.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mssql/json.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mssql/provision.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mssql/pymssql.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mssql/pyodbc.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/aiomysql.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/asyncmy.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/dml.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/enumerated.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/expression.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/json.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadb.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadbconnector.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/provision.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/reflection.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/reserved_words.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/types.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/aiomysql.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/asyncmy.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/base.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/cymysql.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/dml.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/enumerated.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/expression.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/json.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/mariadb.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/mariadbconnector.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/mysqlconnector.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/mysqldb.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/provision.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/pymysql.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/pyodbc.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/reflection.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/reserved_words.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/mysql/types.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/oracle/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/dictionary.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/oracledb.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/provision.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/types.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/oracle/base.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/oracle/cx_oracle.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/oracle/dictionary.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/oracle/oracledb.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/oracle/provision.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/oracle/types.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/_psycopg_common.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/array.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/asyncpg.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/dml.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ext.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/json.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/named_types.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg_catalog.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/provision.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2cffi.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/types.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/_psycopg_common.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/array.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/base.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/dml.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/ext.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/hstore.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/json.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/named_types.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/pg8000.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/pg_catalog.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/provision.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/psycopg.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/psycopg2.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/psycopg2cffi.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/ranges.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/postgresql/types.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/aiosqlite.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/dml.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/json.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/provision.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlcipher.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/sqlite/aiosqlite.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/sqlite/base.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/sqlite/dml.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/sqlite/json.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/sqlite/provision.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/sqlite/pysqlcipher.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/sqlite/pysqlite.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/dialects/type_migration_guidelines.txt create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_processors.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_row.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/characteristics.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/create.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/cursor.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/default.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/events.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/interfaces.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/mock.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/processors.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/reflection.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/result.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/row.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/strategies.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/url.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/__pycache__/util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/_py_processors.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/_py_row.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/_py_util.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/base.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/characteristics.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/create.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/cursor.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/default.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/events.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/interfaces.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/mock.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/processors.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/reflection.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/result.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/row.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/strategies.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/url.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/engine/util.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/event/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/event/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/event/__pycache__/api.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/event/__pycache__/attr.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/event/__pycache__/base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/event/__pycache__/legacy.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/event/__pycache__/registry.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/event/api.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/event/attr.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/event/base.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/event/legacy.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/event/registry.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/events.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/exc.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/__pycache__/associationproxy.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/__pycache__/automap.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/__pycache__/baked.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/__pycache__/compiler.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/__pycache__/horizontal_shard.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/__pycache__/hybrid.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/__pycache__/indexable.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/__pycache__/instrumentation.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/__pycache__/mutable.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/__pycache__/orderinglist.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/__pycache__/serializer.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/associationproxy.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/asyncio/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/engine.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/exc.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/result.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/scoping.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/session.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/asyncio/base.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/asyncio/engine.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/asyncio/exc.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/asyncio/result.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/asyncio/scoping.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/asyncio/session.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/automap.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/baked.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/compiler.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/declarative/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/declarative/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/declarative/__pycache__/extensions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/declarative/extensions.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/horizontal_shard.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/hybrid.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/indexable.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/instrumentation.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/mutable.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/mypy/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/apply.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/decl_class.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/infer.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/names.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/plugin.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/mypy/apply.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/mypy/decl_class.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/mypy/infer.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/mypy/names.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/mypy/plugin.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/mypy/util.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/orderinglist.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/ext/serializer.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/future/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/future/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/future/__pycache__/engine.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/future/engine.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/inspection.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/log.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/_orm_constructors.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/_typing.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/attributes.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/bulk_persistence.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/clsregistry.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/collections.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/context.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/decl_api.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/decl_base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/dependency.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/descriptor_props.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/dynamic.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/evaluator.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/events.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/exc.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/identity.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/instrumentation.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/interfaces.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/loading.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/mapped_collection.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/mapper.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/path_registry.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/persistence.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/properties.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/query.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/relationships.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/scoping.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/session.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/state.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/state_changes.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/strategies.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/strategy_options.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/sync.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/unitofwork.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/__pycache__/writeonly.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/_orm_constructors.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/_typing.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/attributes.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/base.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/bulk_persistence.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/clsregistry.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/collections.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/context.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/decl_api.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/decl_base.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/dependency.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/descriptor_props.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/dynamic.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/evaluator.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/events.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/exc.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/identity.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/instrumentation.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/interfaces.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/loading.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/mapped_collection.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/mapper.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/path_registry.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/persistence.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/properties.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/query.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/relationships.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/scoping.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/session.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/state.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/state_changes.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/strategies.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/strategy_options.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/sync.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/unitofwork.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/util.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/orm/writeonly.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/pool/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/pool/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/pool/__pycache__/base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/pool/__pycache__/events.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/pool/__pycache__/impl.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/pool/base.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/pool/events.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/pool/impl.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/py.typed create mode 100644 .venv/Lib/site-packages/sqlalchemy/schema.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_dml_constructors.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_elements_constructors.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_orm_types.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_py_util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_selectable_constructors.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_typing.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/annotation.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/cache_key.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/coercions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/compiler.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/crud.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/ddl.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/default_comparator.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/dml.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/elements.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/events.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/expression.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/functions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/lambdas.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/naming.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/operators.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/roles.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/schema.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/selectable.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/sqltypes.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/traversals.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/type_api.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/__pycache__/visitors.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/_dml_constructors.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/_elements_constructors.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/_orm_types.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/_py_util.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/_selectable_constructors.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/_typing.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/annotation.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/base.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/cache_key.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/coercions.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/compiler.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/crud.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/ddl.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/default_comparator.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/dml.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/elements.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/events.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/expression.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/functions.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/lambdas.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/naming.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/operators.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/roles.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/schema.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/selectable.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/sqltypes.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/traversals.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/type_api.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/util.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/sql/visitors.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/__pycache__/assertions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/__pycache__/assertsql.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/__pycache__/asyncio.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/__pycache__/config.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/__pycache__/engines.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/__pycache__/entities.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/__pycache__/exclusions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/__pycache__/fixtures.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/__pycache__/pickleable.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/__pycache__/profiling.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/__pycache__/provision.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/__pycache__/requirements.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/__pycache__/schema.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/__pycache__/util.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/__pycache__/warnings.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/assertions.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/assertsql.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/asyncio.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/config.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/engines.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/entities.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/exclusions.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/fixtures.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/pickleable.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/plugin/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/bootstrap.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/plugin/bootstrap.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/plugin/plugin_base.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/plugin/pytestplugin.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/profiling.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/provision.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/requirements.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/schema.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_cte.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_deprecations.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_dialect.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_insert.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_results.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_rowcount.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_select.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_types.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_unicode_ddl.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/test_cte.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/test_ddl.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/test_deprecations.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/test_dialect.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/test_insert.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/test_reflection.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/test_results.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/test_rowcount.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/test_select.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/test_sequence.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/test_types.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/test_unicode_ddl.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/suite/test_update_delete.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/util.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/testing/warnings.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/types.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/__init__.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/__pycache__/_collections.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/__pycache__/_concurrency_py3k.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/__pycache__/_has_cy.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/__pycache__/_py_collections.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/__pycache__/compat.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/__pycache__/concurrency.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/__pycache__/deprecations.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/__pycache__/langhelpers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/__pycache__/preloaded.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/__pycache__/queue.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/__pycache__/tool_support.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/__pycache__/topological.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/__pycache__/typing.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/_collections.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/_concurrency_py3k.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/_has_cy.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/_py_collections.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/compat.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/concurrency.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/deprecations.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/langhelpers.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/preloaded.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/queue.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/tool_support.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/topological.py create mode 100644 .venv/Lib/site-packages/sqlalchemy/util/typing.py create mode 100644 .venv/Lib/site-packages/typing_extensions-4.5.0.dist-info/INSTALLER create mode 100644 .venv/Lib/site-packages/typing_extensions-4.5.0.dist-info/LICENSE create mode 100644 .venv/Lib/site-packages/typing_extensions-4.5.0.dist-info/METADATA create mode 100644 .venv/Lib/site-packages/typing_extensions-4.5.0.dist-info/RECORD create mode 100644 .venv/Lib/site-packages/typing_extensions-4.5.0.dist-info/WHEEL create mode 100644 .venv/Lib/site-packages/typing_extensions.py create mode 100644 .venv/Lib/site-packages/werkzeug/__init__.py create mode 100644 .venv/Lib/site-packages/werkzeug/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/__pycache__/_internal.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/__pycache__/_reloader.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/__pycache__/exceptions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/__pycache__/formparser.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/__pycache__/http.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/__pycache__/local.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/__pycache__/security.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/__pycache__/serving.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/__pycache__/test.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/__pycache__/testapp.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/__pycache__/urls.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/__pycache__/user_agent.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/__pycache__/utils.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/__pycache__/wsgi.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/_internal.py create mode 100644 .venv/Lib/site-packages/werkzeug/_reloader.py create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/__init__.py create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/__pycache__/accept.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/__pycache__/auth.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/__pycache__/cache_control.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/__pycache__/csp.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/__pycache__/etag.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/__pycache__/file_storage.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/__pycache__/headers.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/__pycache__/mixins.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/__pycache__/range.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/__pycache__/structures.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/accept.py create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/accept.pyi create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/auth.py create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/cache_control.py create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/cache_control.pyi create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/csp.py create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/csp.pyi create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/etag.py create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/etag.pyi create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/file_storage.py create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/file_storage.pyi create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/headers.py create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/headers.pyi create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/mixins.py create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/mixins.pyi create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/range.py create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/range.pyi create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/structures.py create mode 100644 .venv/Lib/site-packages/werkzeug/datastructures/structures.pyi create mode 100644 .venv/Lib/site-packages/werkzeug/debug/__init__.py create mode 100644 .venv/Lib/site-packages/werkzeug/debug/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/debug/__pycache__/console.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/debug/__pycache__/repr.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/debug/__pycache__/tbtools.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/debug/console.py create mode 100644 .venv/Lib/site-packages/werkzeug/debug/repr.py create mode 100644 .venv/Lib/site-packages/werkzeug/debug/shared/ICON_LICENSE.md create mode 100644 .venv/Lib/site-packages/werkzeug/debug/shared/console.png create mode 100644 .venv/Lib/site-packages/werkzeug/debug/shared/debugger.js create mode 100644 .venv/Lib/site-packages/werkzeug/debug/shared/less.png create mode 100644 .venv/Lib/site-packages/werkzeug/debug/shared/more.png create mode 100644 .venv/Lib/site-packages/werkzeug/debug/shared/style.css create mode 100644 .venv/Lib/site-packages/werkzeug/debug/tbtools.py create mode 100644 .venv/Lib/site-packages/werkzeug/exceptions.py create mode 100644 .venv/Lib/site-packages/werkzeug/formparser.py create mode 100644 .venv/Lib/site-packages/werkzeug/http.py create mode 100644 .venv/Lib/site-packages/werkzeug/local.py create mode 100644 .venv/Lib/site-packages/werkzeug/middleware/__init__.py create mode 100644 .venv/Lib/site-packages/werkzeug/middleware/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/middleware/__pycache__/dispatcher.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/middleware/__pycache__/http_proxy.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/middleware/__pycache__/lint.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/middleware/__pycache__/profiler.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/middleware/__pycache__/proxy_fix.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/middleware/__pycache__/shared_data.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/middleware/dispatcher.py create mode 100644 .venv/Lib/site-packages/werkzeug/middleware/http_proxy.py create mode 100644 .venv/Lib/site-packages/werkzeug/middleware/lint.py create mode 100644 .venv/Lib/site-packages/werkzeug/middleware/profiler.py create mode 100644 .venv/Lib/site-packages/werkzeug/middleware/proxy_fix.py create mode 100644 .venv/Lib/site-packages/werkzeug/middleware/shared_data.py create mode 100644 .venv/Lib/site-packages/werkzeug/py.typed create mode 100644 .venv/Lib/site-packages/werkzeug/routing/__init__.py create mode 100644 .venv/Lib/site-packages/werkzeug/routing/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/routing/__pycache__/converters.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/routing/__pycache__/exceptions.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/routing/__pycache__/map.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/routing/__pycache__/matcher.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/routing/__pycache__/rules.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/routing/converters.py create mode 100644 .venv/Lib/site-packages/werkzeug/routing/exceptions.py create mode 100644 .venv/Lib/site-packages/werkzeug/routing/map.py create mode 100644 .venv/Lib/site-packages/werkzeug/routing/matcher.py create mode 100644 .venv/Lib/site-packages/werkzeug/routing/rules.py create mode 100644 .venv/Lib/site-packages/werkzeug/sansio/__init__.py create mode 100644 .venv/Lib/site-packages/werkzeug/sansio/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/sansio/__pycache__/http.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/sansio/__pycache__/multipart.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/sansio/__pycache__/request.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/sansio/__pycache__/response.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/sansio/__pycache__/utils.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/sansio/http.py create mode 100644 .venv/Lib/site-packages/werkzeug/sansio/multipart.py create mode 100644 .venv/Lib/site-packages/werkzeug/sansio/request.py create mode 100644 .venv/Lib/site-packages/werkzeug/sansio/response.py create mode 100644 .venv/Lib/site-packages/werkzeug/sansio/utils.py create mode 100644 .venv/Lib/site-packages/werkzeug/security.py create mode 100644 .venv/Lib/site-packages/werkzeug/serving.py create mode 100644 .venv/Lib/site-packages/werkzeug/test.py create mode 100644 .venv/Lib/site-packages/werkzeug/testapp.py create mode 100644 .venv/Lib/site-packages/werkzeug/urls.py create mode 100644 .venv/Lib/site-packages/werkzeug/user_agent.py create mode 100644 .venv/Lib/site-packages/werkzeug/utils.py create mode 100644 .venv/Lib/site-packages/werkzeug/wrappers/__init__.py create mode 100644 .venv/Lib/site-packages/werkzeug/wrappers/__pycache__/__init__.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/wrappers/__pycache__/request.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/wrappers/__pycache__/response.cpython-311.pyc create mode 100644 .venv/Lib/site-packages/werkzeug/wrappers/request.py create mode 100644 .venv/Lib/site-packages/werkzeug/wrappers/response.py create mode 100644 .venv/Lib/site-packages/werkzeug/wsgi.py create mode 100644 .venv/Scripts/Activate.ps1 create mode 100644 .venv/Scripts/activate create mode 100644 .venv/Scripts/activate.bat create mode 100644 .venv/Scripts/deactivate.bat create mode 100644 .venv/Scripts/flask.exe create mode 100644 .venv/Scripts/pip.exe create mode 100644 .venv/Scripts/pip3.11.exe create mode 100644 .venv/Scripts/pip3.exe create mode 100644 .venv/Scripts/python.exe create mode 100644 .venv/Scripts/pythonw.exe create mode 100644 .venv/pyvenv.cfg create mode 100644 instance/database.db diff --git a/.venv/Include/site/python3.11/greenlet/greenlet.h b/.venv/Include/site/python3.11/greenlet/greenlet.h new file mode 100644 index 000000000..d02a16e43 --- /dev/null +++ b/.venv/Include/site/python3.11/greenlet/greenlet.h @@ -0,0 +1,164 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ + +/* Greenlet object interface */ + +#ifndef Py_GREENLETOBJECT_H +#define Py_GREENLETOBJECT_H + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is deprecated and undocumented. It does not change. */ +#define GREENLET_VERSION "1.0.0" + +#ifndef GREENLET_MODULE +#define implementation_ptr_t void* +#endif + +typedef struct _greenlet { + PyObject_HEAD + PyObject* weakreflist; + PyObject* dict; + implementation_ptr_t pimpl; +} PyGreenlet; + +#define PyGreenlet_Check(op) (op && PyObject_TypeCheck(op, &PyGreenlet_Type)) + + +/* C API functions */ + +/* Total number of symbols that are exported */ +#define PyGreenlet_API_pointers 12 + +#define PyGreenlet_Type_NUM 0 +#define PyExc_GreenletError_NUM 1 +#define PyExc_GreenletExit_NUM 2 + +#define PyGreenlet_New_NUM 3 +#define PyGreenlet_GetCurrent_NUM 4 +#define PyGreenlet_Throw_NUM 5 +#define PyGreenlet_Switch_NUM 6 +#define PyGreenlet_SetParent_NUM 7 + +#define PyGreenlet_MAIN_NUM 8 +#define PyGreenlet_STARTED_NUM 9 +#define PyGreenlet_ACTIVE_NUM 10 +#define PyGreenlet_GET_PARENT_NUM 11 + +#ifndef GREENLET_MODULE +/* This section is used by modules that uses the greenlet C API */ +static void** _PyGreenlet_API = NULL; + +# define PyGreenlet_Type \ + (*(PyTypeObject*)_PyGreenlet_API[PyGreenlet_Type_NUM]) + +# define PyExc_GreenletError \ + ((PyObject*)_PyGreenlet_API[PyExc_GreenletError_NUM]) + +# define PyExc_GreenletExit \ + ((PyObject*)_PyGreenlet_API[PyExc_GreenletExit_NUM]) + +/* + * PyGreenlet_New(PyObject *args) + * + * greenlet.greenlet(run, parent=None) + */ +# define PyGreenlet_New \ + (*(PyGreenlet * (*)(PyObject * run, PyGreenlet * parent)) \ + _PyGreenlet_API[PyGreenlet_New_NUM]) + +/* + * PyGreenlet_GetCurrent(void) + * + * greenlet.getcurrent() + */ +# define PyGreenlet_GetCurrent \ + (*(PyGreenlet * (*)(void)) _PyGreenlet_API[PyGreenlet_GetCurrent_NUM]) + +/* + * PyGreenlet_Throw( + * PyGreenlet *greenlet, + * PyObject *typ, + * PyObject *val, + * PyObject *tb) + * + * g.throw(...) + */ +# define PyGreenlet_Throw \ + (*(PyObject * (*)(PyGreenlet * self, \ + PyObject * typ, \ + PyObject * val, \ + PyObject * tb)) \ + _PyGreenlet_API[PyGreenlet_Throw_NUM]) + +/* + * PyGreenlet_Switch(PyGreenlet *greenlet, PyObject *args) + * + * g.switch(*args, **kwargs) + */ +# define PyGreenlet_Switch \ + (*(PyObject * \ + (*)(PyGreenlet * greenlet, PyObject * args, PyObject * kwargs)) \ + _PyGreenlet_API[PyGreenlet_Switch_NUM]) + +/* + * PyGreenlet_SetParent(PyObject *greenlet, PyObject *new_parent) + * + * g.parent = new_parent + */ +# define PyGreenlet_SetParent \ + (*(int (*)(PyGreenlet * greenlet, PyGreenlet * nparent)) \ + _PyGreenlet_API[PyGreenlet_SetParent_NUM]) + +/* + * PyGreenlet_GetParent(PyObject* greenlet) + * + * return greenlet.parent; + * + * This could return NULL even if there is no exception active. + * If it does not return NULL, you are responsible for decrementing the + * reference count. + */ +# define PyGreenlet_GetParent \ + (*(PyGreenlet* (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_GET_PARENT_NUM]) + +/* + * deprecated, undocumented alias. + */ +# define PyGreenlet_GET_PARENT PyGreenlet_GetParent + +# define PyGreenlet_MAIN \ + (*(int (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_MAIN_NUM]) + +# define PyGreenlet_STARTED \ + (*(int (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_STARTED_NUM]) + +# define PyGreenlet_ACTIVE \ + (*(int (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_ACTIVE_NUM]) + + + + +/* Macro that imports greenlet and initializes C API */ +/* NOTE: This has actually moved to ``greenlet._greenlet._C_API``, but we + keep the older definition to be sure older code that might have a copy of + the header still works. */ +# define PyGreenlet_Import() \ + { \ + _PyGreenlet_API = (void**)PyCapsule_Import("greenlet._C_API", 0); \ + } + +#endif /* GREENLET_MODULE */ + +#ifdef __cplusplus +} +#endif +#endif /* !Py_GREENLETOBJECT_H */ diff --git a/.venv/Lib/site-packages/Flask-2.3.2.dist-info/INSTALLER b/.venv/Lib/site-packages/Flask-2.3.2.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/.venv/Lib/site-packages/Flask-2.3.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/Lib/site-packages/Flask-2.3.2.dist-info/LICENSE.rst b/.venv/Lib/site-packages/Flask-2.3.2.dist-info/LICENSE.rst new file mode 100644 index 000000000..9d227a0cc --- /dev/null +++ b/.venv/Lib/site-packages/Flask-2.3.2.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2010 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/.venv/Lib/site-packages/Flask-2.3.2.dist-info/METADATA b/.venv/Lib/site-packages/Flask-2.3.2.dist-info/METADATA new file mode 100644 index 000000000..a99e52fa2 --- /dev/null +++ b/.venv/Lib/site-packages/Flask-2.3.2.dist-info/METADATA @@ -0,0 +1,118 @@ +Metadata-Version: 2.1 +Name: Flask +Version: 2.3.2 +Summary: A simple framework for building complex web applications. +Author-email: Armin Ronacher +Maintainer-email: Pallets +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: Chat, https://discord.gg/pallets +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Framework :: Flask +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application +Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Requires-Python: >=3.8 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst +Requires-Dist: Werkzeug (>=2.3.3) +Requires-Dist: Jinja2 (>=3.1.2) +Requires-Dist: itsdangerous (>=2.1.2) +Requires-Dist: click (>=8.1.3) +Requires-Dist: blinker (>=1.6.2) +Requires-Dist: importlib-metadata (>=3.6.0) ; python_version < "3.10" +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/ +- Chat: https://discord.gg/pallets diff --git a/.venv/Lib/site-packages/Flask-2.3.2.dist-info/RECORD b/.venv/Lib/site-packages/Flask-2.3.2.dist-info/RECORD new file mode 100644 index 000000000..37986ce5e --- /dev/null +++ b/.venv/Lib/site-packages/Flask-2.3.2.dist-info/RECORD @@ -0,0 +1,54 @@ +../../Scripts/flask.exe,sha256=sHbRv7GJWspjsAJMftC44xyduFQmvWfZDDj4-gy39_s,108420 +Flask-2.3.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Flask-2.3.2.dist-info/LICENSE.rst,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +Flask-2.3.2.dist-info/METADATA,sha256=o20FsyHfhQR8TMWB_QrtQN2PHyzacLRUAgol_quBBvA,3716 +Flask-2.3.2.dist-info/RECORD,, +Flask-2.3.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +Flask-2.3.2.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92 +Flask-2.3.2.dist-info/entry_points.txt,sha256=s3MqQpduU25y4dq3ftBYD6bMVdVnbMpZP-sUNw0zw0k,41 +Flask-2.3.2.dist-info/top_level.txt,sha256=dvi65F6AeGWVU0TBpYiC04yM60-FX1gJFkK31IKQr5c,6 +flask/__init__.py,sha256=yeirfdSGPoM3Ylc9FWWJfy2gEQlHfiZCKrxBiPefACM,3731 +flask/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30 +flask/__pycache__/__init__.cpython-311.pyc,, +flask/__pycache__/__main__.cpython-311.pyc,, +flask/__pycache__/app.cpython-311.pyc,, +flask/__pycache__/blueprints.cpython-311.pyc,, +flask/__pycache__/cli.cpython-311.pyc,, +flask/__pycache__/config.cpython-311.pyc,, +flask/__pycache__/ctx.cpython-311.pyc,, +flask/__pycache__/debughelpers.cpython-311.pyc,, +flask/__pycache__/globals.cpython-311.pyc,, +flask/__pycache__/helpers.cpython-311.pyc,, +flask/__pycache__/logging.cpython-311.pyc,, +flask/__pycache__/scaffold.cpython-311.pyc,, +flask/__pycache__/sessions.cpython-311.pyc,, +flask/__pycache__/signals.cpython-311.pyc,, +flask/__pycache__/templating.cpython-311.pyc,, +flask/__pycache__/testing.cpython-311.pyc,, +flask/__pycache__/typing.cpython-311.pyc,, +flask/__pycache__/views.cpython-311.pyc,, +flask/__pycache__/wrappers.cpython-311.pyc,, +flask/app.py,sha256=ht3Qx9U9z0I1qUfLoS7bYhJcubdpk-i54eHq37LDlN8,87620 +flask/blueprints.py,sha256=ZpVrwa8UY-YnVDsX_1K10XQjDwCUp7Qn2hmKln5icEQ,24332 +flask/cli.py,sha256=wRxX61jRDKQM4iZsYaVwcgGbpN2_2DmntLMWjVeiAx4,33720 +flask/config.py,sha256=yqdiN7TLOs2EChJ0uhTz3SICA3-QBG6l5wHTIUnANpc,12800 +flask/ctx.py,sha256=x2kGzUXtPzVyi2YSKrU_PV1AvtxTmh2iRdriJRTSPGM,14841 +flask/debughelpers.py,sha256=BR0xkd-sAyFuFW07D6NfrqNwSZxk1IrkG5n8zem-3sw,5547 +flask/globals.py,sha256=KUzVvSPh8v28kUasVDi_aQKB9hI2jZSYQHqaDU2P414,2945 +flask/helpers.py,sha256=QDxFmBW9GGXQDLuXrcxQRL0Ldo-_q11zEt3ZVgfINlI,24957 +flask/json/__init__.py,sha256=pdtpoK2b0b1u7Sxbx3feM7VWhsI20l1yGAvbYWxaxvc,5572 +flask/json/__pycache__/__init__.cpython-311.pyc,, +flask/json/__pycache__/provider.cpython-311.pyc,, +flask/json/__pycache__/tag.cpython-311.pyc,, +flask/json/provider.py,sha256=Os0frb8oGfyWKL-TDxb0Uy-MY6gDhPdJkRaUl5xAOXI,7637 +flask/json/tag.py,sha256=ihb7QWrNEr0YC3KD4TolZbftgSPCuLk7FAvK49huYC0,8871 +flask/logging.py,sha256=lArx2Bq9oTtUJ-DnZL9t88xU2zytzp4UWSM9Bd72NDQ,2327 +flask/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +flask/scaffold.py,sha256=0tYQN98sC93YkIEw9g8BiIwceFZ27tNqBtBtFhFy5tY,35231 +flask/sessions.py,sha256=rFH2QKXG24dEazkKGxAHqUpAUh_30hDHrddhVYgAcY0,14169 +flask/signals.py,sha256=s1H4yKjf3c5dgVr41V6sJpE9dLJvmTJMYuK0rkqx3sw,1146 +flask/templating.py,sha256=XdP2hMFnZ5FCZOG7HUaLjC2VC-b4uHSWlDjwv_1p3qc,7503 +flask/testing.py,sha256=52-m5GecDcA-F2dFEYe8eDwApusxdg6S1suBaSC85N0,9768 +flask/typing.py,sha256=4Lj-YTxUoYvPYofC9GKu-1o0Ht8lyjp9z3I336J13_o,3005 +flask/views.py,sha256=V5hOGZLx0Bn99QGcM6mh5x_uM-MypVT0-RysEFU84jc,6789 +flask/wrappers.py,sha256=PhMp3teK3SnEmIdog59cO_DHiZ9Btn0qI1EifrTdwP8,5709 diff --git a/.venv/Lib/site-packages/Flask-2.3.2.dist-info/REQUESTED b/.venv/Lib/site-packages/Flask-2.3.2.dist-info/REQUESTED new file mode 100644 index 000000000..e69de29bb diff --git a/.venv/Lib/site-packages/Flask-2.3.2.dist-info/WHEEL b/.venv/Lib/site-packages/Flask-2.3.2.dist-info/WHEEL new file mode 100644 index 000000000..1f37c02f2 --- /dev/null +++ b/.venv/Lib/site-packages/Flask-2.3.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.40.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/.venv/Lib/site-packages/Flask-2.3.2.dist-info/entry_points.txt b/.venv/Lib/site-packages/Flask-2.3.2.dist-info/entry_points.txt new file mode 100644 index 000000000..137232d74 --- /dev/null +++ b/.venv/Lib/site-packages/Flask-2.3.2.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +flask = flask.cli:main diff --git a/.venv/Lib/site-packages/Flask-2.3.2.dist-info/top_level.txt b/.venv/Lib/site-packages/Flask-2.3.2.dist-info/top_level.txt new file mode 100644 index 000000000..7e1060246 --- /dev/null +++ b/.venv/Lib/site-packages/Flask-2.3.2.dist-info/top_level.txt @@ -0,0 +1 @@ +flask diff --git a/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/INSTALLER b/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/LICENSE b/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/LICENSE new file mode 100644 index 000000000..04463812d --- /dev/null +++ b/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2011 Matthew Frazier + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/METADATA b/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/METADATA new file mode 100644 index 000000000..ad35eb43c --- /dev/null +++ b/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/METADATA @@ -0,0 +1,183 @@ +Metadata-Version: 2.1 +Name: Flask-Login +Version: 0.6.2 +Summary: User authentication and session management for Flask. +Home-page: https://github.com/maxcountryman/flask-login +Author: Matthew Frazier +Author-email: leafstormrush@gmail.com +Maintainer: Max Countryman +License: MIT +Project-URL: Documentation, https://flask-login.readthedocs.io/ +Project-URL: Changes, https://github.com/maxcountryman/flask-login/blob/main/CHANGES.md +Project-URL: Source Code, https://github.com/maxcountryman/flask-login +Project-URL: Issue Tracker, https://github.com/maxcountryman/flask-login/issues +Classifier: Development Status :: 4 - Beta +Classifier: Environment :: Web Environment +Classifier: Framework :: Flask +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=3.7 +Description-Content-Type: text/markdown +License-File: LICENSE +Requires-Dist: Flask (>=1.0.4) +Requires-Dist: Werkzeug (>=1.0.1) + +# Flask-Login + +![Tests](https://github.com/maxcountryman/flask-login/workflows/Tests/badge.svg) +[![coverage](https://coveralls.io/repos/maxcountryman/flask-login/badge.svg?branch=main&service=github)](https://coveralls.io/github/maxcountryman/flask-login?branch=main) +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE) + +Flask-Login provides user session management for Flask. It handles the common +tasks of logging in, logging out, and remembering your users' sessions over +extended periods of time. + +Flask-Login is not bound to any particular database system or permissions +model. The only requirement is that your user objects implement a few methods, +and that you provide a callback to the extension capable of loading users from +their ID. + +## Installation + +Install the extension with pip: + +```sh +$ pip install flask-login +``` + +## Usage + +Once installed, the Flask-Login is easy to use. Let's walk through setting up +a basic application. Also please note that this is a very basic guide: we will +be taking shortcuts here that you should never take in a real application. + +To begin we'll set up a Flask app: + +```python +import flask + +app = flask.Flask(__name__) +app.secret_key = 'super secret string' # Change this! +``` + +Flask-Login works via a login manager. To kick things off, we'll set up the +login manager by instantiating it and telling it about our Flask app: + +```python +import flask_login + +login_manager = flask_login.LoginManager() + +login_manager.init_app(app) +``` + +To keep things simple we're going to use a dictionary to represent a database +of users. In a real application, this would be an actual persistence layer. +However it's important to point out this is a feature of Flask-Login: it +doesn't care how your data is stored so long as you tell it how to retrieve it! + +```python +# Our mock database. +users = {'foo@bar.tld': {'password': 'secret'}} +``` + +We also need to tell Flask-Login how to load a user from a Flask request and +from its session. To do this we need to define our user object, a +`user_loader` callback, and a `request_loader` callback. + +```python +class User(flask_login.UserMixin): + pass + + +@login_manager.user_loader +def user_loader(email): + if email not in users: + return + + user = User() + user.id = email + return user + + +@login_manager.request_loader +def request_loader(request): + email = request.form.get('email') + if email not in users: + return + + user = User() + user.id = email + return user +``` + +Now we're ready to define our views. We can start with a login view, which will +populate the session with authentication bits. After that we can define a view +that requires authentication. + +```python +@app.route('/login', methods=['GET', 'POST']) +def login(): + if flask.request.method == 'GET': + return ''' +
+ + + +
+ ''' + + email = flask.request.form['email'] + if email in users and flask.request.form['password'] == users[email]['password']: + user = User() + user.id = email + flask_login.login_user(user) + return flask.redirect(flask.url_for('protected')) + + return 'Bad login' + + +@app.route('/protected') +@flask_login.login_required +def protected(): + return 'Logged in as: ' + flask_login.current_user.id +``` + +Finally we can define a view to clear the session and log users out: + +```python +@app.route('/logout') +def logout(): + flask_login.logout_user() + return 'Logged out' +``` + +We now have a basic working application that makes use of session-based +authentication. To round things off, we should provide a callback for login +failures: + +```python +@login_manager.unauthorized_handler +def unauthorized_handler(): + return 'Unauthorized', 401 +``` + +Documentation for Flask-Login is available on [ReadTheDocs](https://flask-login.readthedocs.io/en/latest/). +For complete understanding of available configuration, please refer to the [source code](https://github.com/maxcountryman/flask-login). + + +## Contributing + +We welcome contributions! If you would like to hack on Flask-Login, please +follow these steps: + +1. Fork this repository +2. Make your changes +3. Install the dev requirements with `pip install -r requirements/dev.txt` +4. Submit a pull request after running `tox` (ensure it does not error!) + +Please give us adequate time to review your submission. Thanks! diff --git a/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/RECORD b/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/RECORD new file mode 100644 index 000000000..867bb7ff9 --- /dev/null +++ b/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/RECORD @@ -0,0 +1,23 @@ +Flask_Login-0.6.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Flask_Login-0.6.2.dist-info/LICENSE,sha256=ep37nF2iBO0TcPO2LBPimSoS2h2nB_R-FWiX7rQ0Tls,1059 +Flask_Login-0.6.2.dist-info/METADATA,sha256=e64WTcUek0WEtAZum9pOOw7IyDWFfyZ2YQnw5TMdemY,5803 +Flask_Login-0.6.2.dist-info/RECORD,, +Flask_Login-0.6.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +Flask_Login-0.6.2.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +Flask_Login-0.6.2.dist-info/top_level.txt,sha256=OuXmIpiFnXLvW-iBbW2km7ZIy5EZvwSBnYaOC3Kt7j8,12 +flask_login/__about__.py,sha256=8yOFICsyQVOw1GiWVrJW8spiEtBp97DskGmwiFP5aZQ,389 +flask_login/__init__.py,sha256=wYQiQCikT_Ndp3PhOD-1gRTGCrUPIE-FrjQUrT9aVAg,2681 +flask_login/__pycache__/__about__.cpython-311.pyc,, +flask_login/__pycache__/__init__.cpython-311.pyc,, +flask_login/__pycache__/config.cpython-311.pyc,, +flask_login/__pycache__/login_manager.cpython-311.pyc,, +flask_login/__pycache__/mixins.cpython-311.pyc,, +flask_login/__pycache__/signals.cpython-311.pyc,, +flask_login/__pycache__/test_client.cpython-311.pyc,, +flask_login/__pycache__/utils.cpython-311.pyc,, +flask_login/config.py,sha256=YAocv18La7YGQyNY5aT7rU1GQIZnX6pvchwqx3kA9p8,1813 +flask_login/login_manager.py,sha256=h20F_iv3mqc6rIJ4-V6_XookzOUl8Rcpasua-dCByQY,20073 +flask_login/mixins.py,sha256=gPd7otMRljxw0eUhUMbHsnEBc_jK2cYdxg5KFLuJcoI,1528 +flask_login/signals.py,sha256=xCMoFHKU1RTVt1NY-Gfl0OiVKpiyNt6YJw_PsgkjY3w,2464 +flask_login/test_client.py,sha256=6mrjiBRLGJpgvvFlLypXPTBLiMp0BAN-Ft-uogqC81g,517 +flask_login/utils.py,sha256=RFSbIMPr58gMPRWx3aQ-Co1gZASld-A1W30zwvZDzYM,14020 diff --git a/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/REQUESTED b/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/REQUESTED new file mode 100644 index 000000000..e69de29bb diff --git a/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/WHEEL b/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/WHEEL new file mode 100644 index 000000000..becc9a66e --- /dev/null +++ b/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/top_level.txt b/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/top_level.txt new file mode 100644 index 000000000..31514bd20 --- /dev/null +++ b/.venv/Lib/site-packages/Flask_Login-0.6.2.dist-info/top_level.txt @@ -0,0 +1 @@ +flask_login diff --git a/.venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/INSTALLER b/.venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/.venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/METADATA b/.venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/METADATA new file mode 100644 index 000000000..e7330c26d --- /dev/null +++ b/.venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/METADATA @@ -0,0 +1,107 @@ +Metadata-Version: 2.1 +Name: Flask-SQLAlchemy +Version: 3.0.3 +Summary: Add SQLAlchemy support to your Flask application. +License: BSD-3-Clause +Author-email: Armin Ronacher +Maintainer-email: Pallets +Requires-Python: >=3.7 +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 +Requires-Dist: Flask>=2.2 +Requires-Dist: SQLAlchemy>=1.4.18 +Project-URL: Changes, https://flask-sqlalchemy.palletsprojects.com/changes/ +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://flask-sqlalchemy.palletsprojects.com/ +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Issue Tracker, https://github.com/pallets-eco/flask-sqlalchemy/issues/ +Project-URL: Source Code, https://github.com/pallets-eco/flask-sqlalchemy/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +Description-Content-Type: text/x-rst + +Flask-SQLAlchemy +================ + +Flask-SQLAlchemy is an extension for `Flask`_ that adds support for +`SQLAlchemy`_ to your application. It aims to simplify using SQLAlchemy +with Flask by providing useful defaults and extra helpers that make it +easier to accomplish common tasks. + +.. _Flask: https://palletsprojects.com/p/flask/ +.. _SQLAlchemy: https://www.sqlalchemy.org + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U Flask-SQLAlchemy + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +A Simple Example +---------------- + +.. code-block:: python + + from flask import Flask + from flask_sqlalchemy import SQLAlchemy + + app = Flask(__name__) + app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///example.sqlite" + db = SQLAlchemy(app) + + class User(db.Model): + id = db.Column(db.Integer, primary_key=True) + username = db.Column(db.String, unique=True, nullable=False) + + with app.app_context(): + db.create_all() + + db.session.add(User(username="example")) + db.session.commit() + + users = db.session.execute(db.select(User)).scalars() + + +Contributing +------------ + +For guidance on setting up a development environment and how to make a +contribution to Flask-SQLAlchemy, see the `contributing guidelines`_. + +.. _contributing guidelines: https://github.com/pallets-eco/flask-sqlalchemy/blob/main/CONTRIBUTING.rst + + +Donate +------ + +The Pallets organization develops and supports Flask-SQLAlchemy 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://flask-sqlalchemy.palletsprojects.com/ +- Changes: https://flask-sqlalchemy.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/Flask-SQLAlchemy/ +- Source Code: https://github.com/pallets-eco/flask-sqlalchemy/ +- Issue Tracker: https://github.com/pallets-eco/flask-sqlalchemy/issues/ +- Website: https://palletsprojects.com/ +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets + diff --git a/.venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/RECORD b/.venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/RECORD new file mode 100644 index 000000000..3a406e532 --- /dev/null +++ b/.venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/RECORD @@ -0,0 +1,27 @@ +Flask_SQLAlchemy-3.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Flask_SQLAlchemy-3.0.3.dist-info/METADATA,sha256=kYGg-3MgK-Yg9VsuMWPXPqBINTQJ7wB5S_vJVZaSxYg,3398 +Flask_SQLAlchemy-3.0.3.dist-info/RECORD,, +Flask_SQLAlchemy-3.0.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +Flask_SQLAlchemy-3.0.3.dist-info/WHEEL,sha256=_tUZrwPtr100-R0q5G_f5lOII6s0lN3q8n5zAHueCvs,87 +Flask_SQLAlchemy-3.0.3.dist-info/licenses/LICENSE.rst,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +flask_sqlalchemy/__init__.py,sha256=s8yPkEhC-CMYvZdEbzaeNsmSxEuaJTiihnAMlsHOd1I,1250 +flask_sqlalchemy/__pycache__/__init__.cpython-311.pyc,, +flask_sqlalchemy/__pycache__/cli.cpython-311.pyc,, +flask_sqlalchemy/__pycache__/extension.cpython-311.pyc,, +flask_sqlalchemy/__pycache__/model.cpython-311.pyc,, +flask_sqlalchemy/__pycache__/pagination.cpython-311.pyc,, +flask_sqlalchemy/__pycache__/query.cpython-311.pyc,, +flask_sqlalchemy/__pycache__/record_queries.cpython-311.pyc,, +flask_sqlalchemy/__pycache__/session.cpython-311.pyc,, +flask_sqlalchemy/__pycache__/table.cpython-311.pyc,, +flask_sqlalchemy/__pycache__/track_modifications.cpython-311.pyc,, +flask_sqlalchemy/cli.py,sha256=pg3QDxP36GW2qnwe_CpPtkRhPchyVSGM6zlBNWuNCFE,484 +flask_sqlalchemy/extension.py,sha256=-aPVgIn6p-MUnE4wGM-WcF1kVK3Vu0x4IyWLVDQS0TQ,38220 +flask_sqlalchemy/model.py,sha256=PPjjLV1JrWPDmw5CxthKg_ZMJURtaKmjJWz4hLwqmyw,7102 +flask_sqlalchemy/pagination.py,sha256=m7uKKPbOtGbLXB289O4T1Xg2hiHa1klyqPQC2GloFt8,10953 +flask_sqlalchemy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +flask_sqlalchemy/query.py,sha256=wOAZwxQyv9BHJy2wHF8fDr_8Kc8ipCGtHonE30z9OUE,3752 +flask_sqlalchemy/record_queries.py,sha256=aDgGqUgc3KdrgzldPCx05mUCNHnDTj8VtAzBTWWRO9c,4294 +flask_sqlalchemy/session.py,sha256=yPul6I6dl_kCQ1wMXJ5XMyehPGaYe0c5Aqtbs3NqJuA,3169 +flask_sqlalchemy/table.py,sha256=wAPOy8qwyAxpMwOIUJY4iMOultzz2W0D6xvBkQ7U2CE,859 +flask_sqlalchemy/track_modifications.py,sha256=59pCoxP0D_J50Ckh_r7KtLPn3Bv-nXNmhP4tDNavbs0,2733 diff --git a/.venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/REQUESTED b/.venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/REQUESTED new file mode 100644 index 000000000..e69de29bb diff --git a/.venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/WHEEL b/.venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/WHEEL new file mode 100644 index 000000000..0ebf515cc --- /dev/null +++ b/.venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: pdm-pep517 1.1.1 +Root-Is-Purelib: True +Tag: py3-none-any diff --git a/.venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/licenses/LICENSE.rst b/.venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/licenses/LICENSE.rst new file mode 100644 index 000000000..9d227a0cc --- /dev/null +++ b/.venv/Lib/site-packages/Flask_SQLAlchemy-3.0.3.dist-info/licenses/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2010 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/INSTALLER b/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/LICENSE.rst b/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/LICENSE.rst new file mode 100644 index 000000000..c37cae49e --- /dev/null +++ b/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2007 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/METADATA b/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/METADATA new file mode 100644 index 000000000..f54bb5ca1 --- /dev/null +++ b/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/METADATA @@ -0,0 +1,113 @@ +Metadata-Version: 2.1 +Name: Jinja2 +Version: 3.1.2 +Summary: A very fast and expressive template engine. +Home-page: https://palletsprojects.com/p/jinja/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://jinja.palletsprojects.com/ +Project-URL: Changes, https://jinja.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/jinja/ +Project-URL: Issue Tracker, https://github.com/pallets/jinja/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +Project-URL: Chat, https://discord.gg/pallets +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Text Processing :: Markup :: HTML +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst +Requires-Dist: MarkupSafe (>=2.0) +Provides-Extra: i18n +Requires-Dist: Babel (>=2.7) ; extra == 'i18n' + +Jinja +===== + +Jinja is a fast, expressive, extensible templating engine. Special +placeholders in the template allow writing code similar to Python +syntax. Then the template is passed data to render the final document. + +It includes: + +- Template inheritance and inclusion. +- Define and import macros within templates. +- HTML templates can use autoescaping to prevent XSS from untrusted + user input. +- A sandboxed environment can safely render untrusted templates. +- AsyncIO support for generating templates and calling async + functions. +- I18N support with Babel. +- Templates are compiled to optimized Python code just-in-time and + cached, or can be compiled ahead-of-time. +- Exceptions point to the correct line in templates to make debugging + easier. +- Extensible filters, tests, functions, and even syntax. + +Jinja's philosophy is that while application logic belongs in Python if +possible, it shouldn't make the template designer's job difficult by +restricting functionality too much. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U Jinja2 + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +In A Nutshell +------------- + +.. code-block:: jinja + + {% extends "base.html" %} + {% block title %}Members{% endblock %} + {% block content %} + + {% endblock %} + + +Donate +------ + +The Pallets organization develops and supports Jinja and other popular +packages. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, `please +donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://jinja.palletsprojects.com/ +- Changes: https://jinja.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/Jinja2/ +- Source Code: https://github.com/pallets/jinja/ +- Issue Tracker: https://github.com/pallets/jinja/issues/ +- Website: https://palletsprojects.com/p/jinja/ +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets + + diff --git a/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/RECORD b/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/RECORD new file mode 100644 index 000000000..878712a0e --- /dev/null +++ b/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/RECORD @@ -0,0 +1,58 @@ +Jinja2-3.1.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Jinja2-3.1.2.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 +Jinja2-3.1.2.dist-info/METADATA,sha256=PZ6v2SIidMNixR7MRUX9f7ZWsPwtXanknqiZUmRbh4U,3539 +Jinja2-3.1.2.dist-info/RECORD,, +Jinja2-3.1.2.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +Jinja2-3.1.2.dist-info/entry_points.txt,sha256=zRd62fbqIyfUpsRtU7EVIFyiu1tPwfgO7EvPErnxgTE,59 +Jinja2-3.1.2.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7 +jinja2/__init__.py,sha256=8vGduD8ytwgD6GDSqpYc2m3aU-T7PKOAddvVXgGr_Fs,1927 +jinja2/__pycache__/__init__.cpython-311.pyc,, +jinja2/__pycache__/_identifier.cpython-311.pyc,, +jinja2/__pycache__/async_utils.cpython-311.pyc,, +jinja2/__pycache__/bccache.cpython-311.pyc,, +jinja2/__pycache__/compiler.cpython-311.pyc,, +jinja2/__pycache__/constants.cpython-311.pyc,, +jinja2/__pycache__/debug.cpython-311.pyc,, +jinja2/__pycache__/defaults.cpython-311.pyc,, +jinja2/__pycache__/environment.cpython-311.pyc,, +jinja2/__pycache__/exceptions.cpython-311.pyc,, +jinja2/__pycache__/ext.cpython-311.pyc,, +jinja2/__pycache__/filters.cpython-311.pyc,, +jinja2/__pycache__/idtracking.cpython-311.pyc,, +jinja2/__pycache__/lexer.cpython-311.pyc,, +jinja2/__pycache__/loaders.cpython-311.pyc,, +jinja2/__pycache__/meta.cpython-311.pyc,, +jinja2/__pycache__/nativetypes.cpython-311.pyc,, +jinja2/__pycache__/nodes.cpython-311.pyc,, +jinja2/__pycache__/optimizer.cpython-311.pyc,, +jinja2/__pycache__/parser.cpython-311.pyc,, +jinja2/__pycache__/runtime.cpython-311.pyc,, +jinja2/__pycache__/sandbox.cpython-311.pyc,, +jinja2/__pycache__/tests.cpython-311.pyc,, +jinja2/__pycache__/utils.cpython-311.pyc,, +jinja2/__pycache__/visitor.cpython-311.pyc,, +jinja2/_identifier.py,sha256=_zYctNKzRqlk_murTNlzrju1FFJL7Va_Ijqqd7ii2lU,1958 +jinja2/async_utils.py,sha256=dHlbTeaxFPtAOQEYOGYh_PHcDT0rsDaUJAFDl_0XtTg,2472 +jinja2/bccache.py,sha256=mhz5xtLxCcHRAa56azOhphIAe19u1we0ojifNMClDio,14061 +jinja2/compiler.py,sha256=Gs-N8ThJ7OWK4-reKoO8Wh1ZXz95MVphBKNVf75qBr8,72172 +jinja2/constants.py,sha256=GMoFydBF_kdpaRKPoM5cl5MviquVRLVyZtfp5-16jg0,1433 +jinja2/debug.py,sha256=iWJ432RadxJNnaMOPrjIDInz50UEgni3_HKuFXi2vuQ,6299 +jinja2/defaults.py,sha256=boBcSw78h-lp20YbaXSJsqkAI2uN_mD_TtCydpeq5wU,1267 +jinja2/environment.py,sha256=6uHIcc7ZblqOMdx_uYNKqRnnwAF0_nzbyeMP9FFtuh4,61349 +jinja2/exceptions.py,sha256=ioHeHrWwCWNaXX1inHmHVblvc4haO7AXsjCp3GfWvx0,5071 +jinja2/ext.py,sha256=ivr3P7LKbddiXDVez20EflcO3q2aHQwz9P_PgWGHVqE,31502 +jinja2/filters.py,sha256=9js1V-h2RlyW90IhLiBGLM2U-k6SCy2F4BUUMgB3K9Q,53509 +jinja2/idtracking.py,sha256=GfNmadir4oDALVxzn3DL9YInhJDr69ebXeA2ygfuCGA,10704 +jinja2/lexer.py,sha256=DW2nX9zk-6MWp65YR2bqqj0xqCvLtD-u9NWT8AnFRxQ,29726 +jinja2/loaders.py,sha256=BfptfvTVpClUd-leMkHczdyPNYFzp_n7PKOJ98iyHOg,23207 +jinja2/meta.py,sha256=GNPEvifmSaU3CMxlbheBOZjeZ277HThOPUTf1RkppKQ,4396 +jinja2/nativetypes.py,sha256=DXgORDPRmVWgy034H0xL8eF7qYoK3DrMxs-935d0Fzk,4226 +jinja2/nodes.py,sha256=i34GPRAZexXMT6bwuf5SEyvdmS-bRCy9KMjwN5O6pjk,34550 +jinja2/optimizer.py,sha256=tHkMwXxfZkbfA1KmLcqmBMSaz7RLIvvItrJcPoXTyD8,1650 +jinja2/parser.py,sha256=nHd-DFHbiygvfaPtm9rcQXJChZG7DPsWfiEsqfwKerY,39595 +jinja2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +jinja2/runtime.py,sha256=5CmD5BjbEJxSiDNTFBeKCaq8qU4aYD2v6q2EluyExms,33476 +jinja2/sandbox.py,sha256=Y0xZeXQnH6EX5VjaV2YixESxoepnRbW_3UeQosaBU3M,14584 +jinja2/tests.py,sha256=Am5Z6Lmfr2XaH_npIfJJ8MdXtWsbLjMULZJulTAj30E,5905 +jinja2/utils.py,sha256=u9jXESxGn8ATZNVolwmkjUVu4SA-tLgV0W7PcSfPfdQ,23965 +jinja2/visitor.py,sha256=MH14C6yq24G_KVtWzjwaI7Wg14PCJIYlWW1kpkxYak0,3568 diff --git a/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/WHEEL b/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/WHEEL new file mode 100644 index 000000000..becc9a66e --- /dev/null +++ b/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/entry_points.txt b/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/entry_points.txt new file mode 100644 index 000000000..7b9666c8e --- /dev/null +++ b/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[babel.extractors] +jinja2 = jinja2.ext:babel_extract[i18n] diff --git a/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/top_level.txt b/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/top_level.txt new file mode 100644 index 000000000..7f7afbf3b --- /dev/null +++ b/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/top_level.txt @@ -0,0 +1 @@ +jinja2 diff --git a/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/INSTALLER b/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/LICENSE.rst b/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/LICENSE.rst new file mode 100644 index 000000000..9d227a0cc --- /dev/null +++ b/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2010 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/METADATA b/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/METADATA new file mode 100644 index 000000000..4a3499979 --- /dev/null +++ b/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/METADATA @@ -0,0 +1,98 @@ +Metadata-Version: 2.1 +Name: MarkupSafe +Version: 2.1.2 +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 +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/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/RECORD b/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/RECORD new file mode 100644 index 000000000..c5f0dc5bd --- /dev/null +++ b/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/RECORD @@ -0,0 +1,14 @@ +MarkupSafe-2.1.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +MarkupSafe-2.1.2.dist-info/LICENSE.rst,sha256=RjHsDbX9kKVH4zaBcmTGeYIUM4FG-KyUtKV_lu6MnsQ,1503 +MarkupSafe-2.1.2.dist-info/METADATA,sha256=ssoeAqYVQV6nsxhzPCWhxmqKxt6n3UYhQgIK6jsKcQA,3320 +MarkupSafe-2.1.2.dist-info/RECORD,, +MarkupSafe-2.1.2.dist-info/WHEEL,sha256=wklNeoByNLhdCl-oEQTdaHIeDl4q9zaQVqAlPxUEgLU,102 +MarkupSafe-2.1.2.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11 +markupsafe/__init__.py,sha256=EzD_fL7cQoePn5mS9RLGLMxz7ApdZSTxpgcDStgPYxA,9601 +markupsafe/__pycache__/__init__.cpython-311.pyc,, +markupsafe/__pycache__/_native.cpython-311.pyc,, +markupsafe/_native.py,sha256=_Q7UsXCOvgdonCgqG3l5asANI6eo50EKnDM-mlwEC5M,1776 +markupsafe/_speedups.c,sha256=n3jzzaJwXcoN8nTFyA53f3vSqsWK2vujI-v6QYifjhQ,7403 +markupsafe/_speedups.cp311-win_amd64.pyd,sha256=B-fTF6ziO3SFE6KQVoZFnxsqD-qhhzKBmFbbPPjPneA,15872 +markupsafe/_speedups.pyi,sha256=f5QtwIOP0eLrxh2v5p6SmaYmlcHIGIfmz0DovaqL0OU,238 +markupsafe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/WHEEL b/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/WHEEL new file mode 100644 index 000000000..7d9ab249c --- /dev/null +++ b/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.38.4) +Root-Is-Purelib: false +Tag: cp311-cp311-win_amd64 + diff --git a/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/top_level.txt b/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/top_level.txt new file mode 100644 index 000000000..75bf72925 --- /dev/null +++ b/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/top_level.txt @@ -0,0 +1 @@ +markupsafe diff --git a/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/INSTALLER b/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/LICENSE b/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/LICENSE new file mode 100644 index 000000000..7bf9bbe96 --- /dev/null +++ b/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/LICENSE @@ -0,0 +1,19 @@ +Copyright 2005-2023 SQLAlchemy authors and contributors . + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/METADATA b/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/METADATA new file mode 100644 index 000000000..6070dd8df --- /dev/null +++ b/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/METADATA @@ -0,0 +1,236 @@ +Metadata-Version: 2.1 +Name: SQLAlchemy +Version: 2.0.13 +Summary: Database Abstraction Library +Home-page: https://www.sqlalchemy.org +Author: Mike Bayer +Author-email: mike_mp@zzzcomputing.com +License: MIT +Project-URL: Documentation, https://docs.sqlalchemy.org +Project-URL: Issue Tracker, https://github.com/sqlalchemy/sqlalchemy/ +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Database :: Front-Ends +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE +Requires-Dist: typing-extensions (>=4.2.0) +Requires-Dist: greenlet (!=0.4.17) ; platform_machine == "aarch64" or (platform_machine == "ppc64le" or (platform_machine == "x86_64" or (platform_machine == "amd64" or (platform_machine == "AMD64" or (platform_machine == "win32" or platform_machine == "WIN32"))))) +Requires-Dist: importlib-metadata ; python_version < "3.8" +Provides-Extra: aiomysql +Requires-Dist: greenlet (!=0.4.17) ; extra == 'aiomysql' +Requires-Dist: aiomysql ; extra == 'aiomysql' +Provides-Extra: aiosqlite +Requires-Dist: greenlet (!=0.4.17) ; extra == 'aiosqlite' +Requires-Dist: aiosqlite ; extra == 'aiosqlite' +Requires-Dist: typing-extensions (!=3.10.0.1) ; extra == 'aiosqlite' +Provides-Extra: asyncio +Requires-Dist: greenlet (!=0.4.17) ; extra == 'asyncio' +Provides-Extra: asyncmy +Requires-Dist: greenlet (!=0.4.17) ; extra == 'asyncmy' +Requires-Dist: asyncmy (!=0.2.4,!=0.2.6,>=0.2.3) ; extra == 'asyncmy' +Provides-Extra: mariadb_connector +Requires-Dist: mariadb (!=1.1.2,!=1.1.5,>=1.0.1) ; extra == 'mariadb_connector' +Provides-Extra: mssql +Requires-Dist: pyodbc ; extra == 'mssql' +Provides-Extra: mssql_pymssql +Requires-Dist: pymssql ; extra == 'mssql_pymssql' +Provides-Extra: mssql_pyodbc +Requires-Dist: pyodbc ; extra == 'mssql_pyodbc' +Provides-Extra: mypy +Requires-Dist: mypy (>=0.910) ; extra == 'mypy' +Provides-Extra: mysql +Requires-Dist: mysqlclient (>=1.4.0) ; extra == 'mysql' +Provides-Extra: mysql_connector +Requires-Dist: mysql-connector-python ; extra == 'mysql_connector' +Provides-Extra: oracle +Requires-Dist: cx-oracle (>=7) ; extra == 'oracle' +Provides-Extra: oracle_oracledb +Requires-Dist: oracledb (>=1.0.1) ; extra == 'oracle_oracledb' +Provides-Extra: postgresql +Requires-Dist: psycopg2 (>=2.7) ; extra == 'postgresql' +Provides-Extra: postgresql_asyncpg +Requires-Dist: greenlet (!=0.4.17) ; extra == 'postgresql_asyncpg' +Requires-Dist: asyncpg ; extra == 'postgresql_asyncpg' +Provides-Extra: postgresql_pg8000 +Requires-Dist: pg8000 (>=1.29.1) ; extra == 'postgresql_pg8000' +Provides-Extra: postgresql_psycopg +Requires-Dist: psycopg (>=3.0.7) ; extra == 'postgresql_psycopg' +Provides-Extra: postgresql_psycopg2binary +Requires-Dist: psycopg2-binary ; extra == 'postgresql_psycopg2binary' +Provides-Extra: postgresql_psycopg2cffi +Requires-Dist: psycopg2cffi ; extra == 'postgresql_psycopg2cffi' +Provides-Extra: pymysql +Requires-Dist: pymysql ; extra == 'pymysql' +Provides-Extra: sqlcipher +Requires-Dist: sqlcipher3-binary ; extra == 'sqlcipher' + +SQLAlchemy +========== + +|PyPI| |Python| |Downloads| + +.. |PyPI| image:: https://img.shields.io/pypi/v/sqlalchemy + :target: https://pypi.org/project/sqlalchemy + :alt: PyPI + +.. |Python| image:: https://img.shields.io/pypi/pyversions/sqlalchemy + :target: https://pypi.org/project/sqlalchemy + :alt: PyPI - Python Version + +.. |Downloads| image:: https://img.shields.io/pypi/dm/sqlalchemy + :target: https://pypi.org/project/sqlalchemy + :alt: PyPI - Downloads + + +The Python SQL Toolkit and Object Relational Mapper + +Introduction +------------- + +SQLAlchemy is the Python SQL toolkit and Object Relational Mapper +that gives application developers the full power and +flexibility of SQL. SQLAlchemy provides a full suite +of well known enterprise-level persistence patterns, +designed for efficient and high-performing database +access, adapted into a simple and Pythonic domain +language. + +Major SQLAlchemy features include: + +* An industrial strength ORM, built + from the core on the identity map, unit of work, + and data mapper patterns. These patterns + allow transparent persistence of objects + using a declarative configuration system. + Domain models + can be constructed and manipulated naturally, + and changes are synchronized with the + current transaction automatically. +* A relationally-oriented query system, exposing + the full range of SQL's capabilities + explicitly, including joins, subqueries, + correlation, and most everything else, + in terms of the object model. + Writing queries with the ORM uses the same + techniques of relational composition you use + when writing SQL. While you can drop into + literal SQL at any time, it's virtually never + needed. +* A comprehensive and flexible system + of eager loading for related collections and objects. + Collections are cached within a session, + and can be loaded on individual access, all + at once using joins, or by query per collection + across the full result set. +* A Core SQL construction system and DBAPI + interaction layer. The SQLAlchemy Core is + separate from the ORM and is a full database + abstraction layer in its own right, and includes + an extensible Python-based SQL expression + language, schema metadata, connection pooling, + type coercion, and custom types. +* All primary and foreign key constraints are + assumed to be composite and natural. Surrogate + integer primary keys are of course still the + norm, but SQLAlchemy never assumes or hardcodes + to this model. +* Database introspection and generation. Database + schemas can be "reflected" in one step into + Python structures representing database metadata; + those same structures can then generate + CREATE statements right back out - all within + the Core, independent of the ORM. + +SQLAlchemy's philosophy: + +* SQL databases behave less and less like object + collections the more size and performance start to + matter; object collections behave less and less like + tables and rows the more abstraction starts to matter. + SQLAlchemy aims to accommodate both of these + principles. +* An ORM doesn't need to hide the "R". A relational + database provides rich, set-based functionality + that should be fully exposed. SQLAlchemy's + ORM provides an open-ended set of patterns + that allow a developer to construct a custom + mediation layer between a domain model and + a relational schema, turning the so-called + "object relational impedance" issue into + a distant memory. +* The developer, in all cases, makes all decisions + regarding the design, structure, and naming conventions + of both the object model as well as the relational + schema. SQLAlchemy only provides the means + to automate the execution of these decisions. +* With SQLAlchemy, there's no such thing as + "the ORM generated a bad query" - you + retain full control over the structure of + queries, including how joins are organized, + how subqueries and correlation is used, what + columns are requested. Everything SQLAlchemy + does is ultimately the result of a developer-initiated + decision. +* Don't use an ORM if the problem doesn't need one. + SQLAlchemy consists of a Core and separate ORM + component. The Core offers a full SQL expression + language that allows Pythonic construction + of SQL constructs that render directly to SQL + strings for a target database, returning + result sets that are essentially enhanced DBAPI + cursors. +* Transactions should be the norm. With SQLAlchemy's + ORM, nothing goes to permanent storage until + commit() is called. SQLAlchemy encourages applications + to create a consistent means of delineating + the start and end of a series of operations. +* Never render a literal value in a SQL statement. + Bound parameters are used to the greatest degree + possible, allowing query optimizers to cache + query plans effectively and making SQL injection + attacks a non-issue. + +Documentation +------------- + +Latest documentation is at: + +https://www.sqlalchemy.org/docs/ + +Installation / Requirements +--------------------------- + +Full documentation for installation is at +`Installation `_. + +Getting Help / Development / Bug reporting +------------------------------------------ + +Please refer to the `SQLAlchemy Community Guide `_. + +Code of Conduct +--------------- + +Above all, SQLAlchemy places great emphasis on polite, thoughtful, and +constructive communication between users and developers. +Please see our current Code of Conduct at +`Code of Conduct `_. + +License +------- + +SQLAlchemy is distributed under the `MIT license +`_. + diff --git a/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/RECORD b/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/RECORD new file mode 100644 index 000000000..facec0241 --- /dev/null +++ b/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/RECORD @@ -0,0 +1,512 @@ +SQLAlchemy-2.0.13.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +SQLAlchemy-2.0.13.dist-info/LICENSE,sha256=ZbcQGZNtpoLy8YjvH-nyoobTdOwtEgtXopPVzxy6pCo,1119 +SQLAlchemy-2.0.13.dist-info/METADATA,sha256=WNY6IVz92VzKC3Wv6loIFJFD06krNms8qCY4JpVEdU0,9566 +SQLAlchemy-2.0.13.dist-info/RECORD,, +SQLAlchemy-2.0.13.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +SQLAlchemy-2.0.13.dist-info/WHEEL,sha256=9wvhO-5NhjjD8YmmxAvXTPQXMDOZ50W5vklzeoqFtkM,102 +SQLAlchemy-2.0.13.dist-info/top_level.txt,sha256=rp-ZgB7D8G11ivXON5VGPjupT1voYmWqkciDt5Uaw_Q,11 +sqlalchemy/__init__.py,sha256=hhqpRr24P7rCUT_baj0rvcETrt1YbblGFkDmRyjt5b0,12811 +sqlalchemy/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/__pycache__/events.cpython-311.pyc,, +sqlalchemy/__pycache__/exc.cpython-311.pyc,, +sqlalchemy/__pycache__/inspection.cpython-311.pyc,, +sqlalchemy/__pycache__/log.cpython-311.pyc,, +sqlalchemy/__pycache__/schema.cpython-311.pyc,, +sqlalchemy/__pycache__/types.cpython-311.pyc,, +sqlalchemy/connectors/__init__.py,sha256=sjPX1Mb2nWgRHLZY0mF350mGiqpi2CYBs2A1b8dh_wE,494 +sqlalchemy/connectors/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/connectors/__pycache__/pyodbc.cpython-311.pyc,, +sqlalchemy/connectors/pyodbc.py,sha256=GFZ_OqBAwQpEprwEmVVCm0imUEqw36PGv1YFOsH2Lag,8730 +sqlalchemy/cyextension/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +sqlalchemy/cyextension/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/cyextension/collections.cp311-win_amd64.pyd,sha256=SM3lHkpPrp7IOSxqjeTgBfo5t_PIhl78XDMEvbfXldY,126464 +sqlalchemy/cyextension/collections.pyx,sha256=UY81HxvMAD4MOFR52SjzUbLHCGGcHZDSfK6gw6AYB8A,12726 +sqlalchemy/cyextension/immutabledict.cp311-win_amd64.pyd,sha256=SkK4w_y10ltRnB0Vzfxvz2RdC6PaU-KRj5krDOPF62g,55296 +sqlalchemy/cyextension/immutabledict.pxd,sha256=JsNJYZIekkbtQQ2Tz6Bn1bO1g07yXztY9bb3rvH1e0Y,43 +sqlalchemy/cyextension/immutabledict.pyx,sha256=VmhtF8aDXjEVVdA80LRY1iP85lNMwcz7vB6hZkAOGB0,3412 +sqlalchemy/cyextension/processors.cp311-win_amd64.pyd,sha256=cWmOiGA9D1oKQoOVe4x8o5CXc-4LHdnKKPLZMG49blA,35328 +sqlalchemy/cyextension/processors.pyx,sha256=ZXuoi-hPRI9pVSbp6QbfJwy6S5kVCUZ8qj_h5-NvAFA,1607 +sqlalchemy/cyextension/resultproxy.cp311-win_amd64.pyd,sha256=mLBo2yCImvhlS_8PvwmtkbtjMXn-MpN5PVa0x6Db05U,41472 +sqlalchemy/cyextension/resultproxy.pyx,sha256=qlk8eBpFo3UYbwQChdIWa3RqWXczuUL8ahulcLCL1bI,2573 +sqlalchemy/cyextension/util.cp311-win_amd64.pyd,sha256=-jes7tQk8MFV2Y9Wu5PhMPfIDIRhEZDPJvhUahQY27g,50176 +sqlalchemy/cyextension/util.pyx,sha256=H2FEg9uAAWO9UcNFyrfVuPhOznTq3h9UdjfmJ2BRD1Y,2374 +sqlalchemy/dialects/__init__.py,sha256=vUDqtIsKolzjds0KK763SAnVCCF1SGQ64zY4WNIxbwM,1847 +sqlalchemy/dialects/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/dialects/mssql/__init__.py,sha256=5HDW8H4RsqXRSS7ZhdzK1t3a8cnbedwC_Mh1_LLuj6o,1929 +sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/dialects/mssql/__pycache__/base.cpython-311.pyc,, +sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-311.pyc,, +sqlalchemy/dialects/mssql/__pycache__/json.cpython-311.pyc,, +sqlalchemy/dialects/mssql/__pycache__/provision.cpython-311.pyc,, +sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-311.pyc,, +sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-311.pyc,, +sqlalchemy/dialects/mssql/base.py,sha256=n99UJRmtJP4pW_YdgvrZKGlPrqUkZwIxgNaJKBNWC4I,136273 +sqlalchemy/dialects/mssql/information_schema.py,sha256=ufbEeGAFsciot3MmKPmFFhW95r57F_ORHULBS_UuUSw,8320 +sqlalchemy/dialects/mssql/json.py,sha256=VOrBSxJWh7Fj-zIBA5aYZwx37DJq1OrWpJqc0xtWPhQ,4700 +sqlalchemy/dialects/mssql/provision.py,sha256=GorD2dznXkX3LvLdpRiOunfKpVhyWZE-Fk6-PUlVxww,5146 +sqlalchemy/dialects/mssql/pymssql.py,sha256=yA5NnGBs0YSzzjnGlqMrtHKdo4XHyJ6zKcySOvAw2ZA,4154 +sqlalchemy/dialects/mssql/pyodbc.py,sha256=1uWGVqSLdbUneZqCa3u6llyVQSTLlOdDX5eS4dT_das,27446 +sqlalchemy/dialects/mysql/__init__.py,sha256=060B9NtuQqUb8vNXDm8bdOGUUi6SUi_757-19DDhOQM,2245 +sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/aiomysql.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/asyncmy.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/base.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/dml.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/enumerated.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/expression.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/json.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/mariadb.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/mariadbconnector.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/provision.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/reflection.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/reserved_words.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/types.cpython-311.pyc,, +sqlalchemy/dialects/mysql/aiomysql.py,sha256=pSkerBf7Ic3xixiEE9nNEnkKpzLhQbShi_iq8X7Nup8,9865 +sqlalchemy/dialects/mysql/asyncmy.py,sha256=4zFz3CAEVVIu3koDklftXrW4nlfKGBEuMPHLb3kYyYU,10147 +sqlalchemy/dialects/mysql/base.py,sha256=lyXh_UGmT90-5L29TJTtipYsbP7QvG7jv2_FC9dKt9w,122516 +sqlalchemy/dialects/mysql/cymysql.py,sha256=RdwzBclxwN3uXWTT34YySR0rQfTjVzZDSadhzlOqhag,2375 +sqlalchemy/dialects/mysql/dml.py,sha256=eB3tx48Dh71eyDEsXJ-6wJMSC1D7XfgN-3S8LWD_BBg,7196 +sqlalchemy/dialects/mysql/enumerated.py,sha256=whCwVR5DmKh455d4EVg2XHItfvLtuzxA5bWOWzK6Cnw,8683 +sqlalchemy/dialects/mysql/expression.py,sha256=-RmnmFCjWn16L_Nn82541wr6I3bUvvMk_6L7WhmeAK4,4206 +sqlalchemy/dialects/mysql/json.py,sha256=hZr1MD4W6BaItKT5LRStDRQbr7wcer4YdWbkh47-RTA,2341 +sqlalchemy/dialects/mysql/mariadb.py,sha256=FNsicKCKgvlAnzwsgmbw-6C_wWLtoNxOulPu6hZDpsc,635 +sqlalchemy/dialects/mysql/mariadbconnector.py,sha256=yajW-43yKl94IxjCCFTzJ1Amr5RRDq0wkvBm_9IGBXU,7703 +sqlalchemy/dialects/mysql/mysqlconnector.py,sha256=8a2BZ_ChVR5HvTzonq0DtYoInD3iV4ihbA_9EbgtUxY,5845 +sqlalchemy/dialects/mysql/mysqldb.py,sha256=4ZLfGACIMD5icglEqx6jTj3W4adT_ANCV1xo5kvAHYw,9962 +sqlalchemy/dialects/mysql/provision.py,sha256=jdtfrsATv7hoMcepkMxHVG5QV2YkA92bg01CnOR9VMs,3327 +sqlalchemy/dialects/mysql/pymysql.py,sha256=f09IxnUy9HFCEnNrW-RqxvByVUREYWRpbHsa1yIPDGk,3045 +sqlalchemy/dialects/mysql/pyodbc.py,sha256=dfz0mekJDsOIvjs5utBRNltUr9YyhYuUH1rsUPb4NjI,4426 +sqlalchemy/dialects/mysql/reflection.py,sha256=4-lXatfmSjcmv7YocofW3WUvLeQV8f0qrn73H40evpg,23198 +sqlalchemy/dialects/mysql/reserved_words.py,sha256=KOR71_hBCzivGutG54Yq_K5t7dT6lgRBey0TcztWI3I,9712 +sqlalchemy/dialects/mysql/types.py,sha256=vOi0kn2OLaWTjPKTNz5xPcS-jiHRLv_l1no_oA_jdYQ,25031 +sqlalchemy/dialects/oracle/__init__.py,sha256=IghimaBtnKRrtkYdO5eFjJ5OUUGPJpYSZZJX0DIJb38,1368 +sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/dialects/oracle/__pycache__/base.cpython-311.pyc,, +sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-311.pyc,, +sqlalchemy/dialects/oracle/__pycache__/dictionary.cpython-311.pyc,, +sqlalchemy/dialects/oracle/__pycache__/oracledb.cpython-311.pyc,, +sqlalchemy/dialects/oracle/__pycache__/provision.cpython-311.pyc,, +sqlalchemy/dialects/oracle/__pycache__/types.cpython-311.pyc,, +sqlalchemy/dialects/oracle/base.py,sha256=b5rHNdX-46XlJtmfTuAoMrOYSi8t24qq2ETIHrsNPXE,121148 +sqlalchemy/dialects/oracle/cx_oracle.py,sha256=mejQuTD-CZ0Q1pGRVKOsc95mHCQaaM1bbVon12r8LnI,56601 +sqlalchemy/dialects/oracle/dictionary.py,sha256=yRmt5b218G1Q5pZR5kF1ocsusT4XAgl3v_t9WhKqlko,19993 +sqlalchemy/dialects/oracle/oracledb.py,sha256=xIV0XStGEb12GccIGcCynZRE6hmzTQ0ZLwZxt9iyRLo,3568 +sqlalchemy/dialects/oracle/provision.py,sha256=KtEVId2eWH9vv4aaXgMB24IOWMoP7mN0fu894YwopIs,8275 +sqlalchemy/dialects/oracle/types.py,sha256=vF5neW-vxJcl9nLL9x74zn05gmU-_wkCTNmF0diqqaw,7738 +sqlalchemy/dialects/postgresql/__init__.py,sha256=kx5Iwob5j2_gYXMVF2qM6qIH5DCXxw1UYXVjuCgpvys,3897 +sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/_psycopg_common.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/array.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/asyncpg.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/base.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/dml.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/ext.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/json.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/named_types.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/pg_catalog.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/provision.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/psycopg.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/psycopg2cffi.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/types.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/_psycopg_common.py,sha256=wxYXBNQ9JGjCc0po1NtIKYsAmRsiuiWRnjOjxEEBbv4,6333 +sqlalchemy/dialects/postgresql/array.py,sha256=-A75IRBO7XtnmO68Xx_iTGCUhHMtXDs4mBNJsQM7_n4,14237 +sqlalchemy/dialects/postgresql/asyncpg.py,sha256=pLa7lmfdlIEp7XCurPnA9tFOE9R7f87Hdfv2_bWf6m0,38223 +sqlalchemy/dialects/postgresql/base.py,sha256=8EdAF2BjMZfRmASQoca2qs8odWMOmkMXPKnPzC7cOJM,172694 +sqlalchemy/dialects/postgresql/dml.py,sha256=V1y-MfMYxXMM9Dx9bjzbWQk49OohxsrM9q5kD_YvpVs,10384 +sqlalchemy/dialects/postgresql/ext.py,sha256=DSGq97egdNnYigNHZ2cd0SvDqdL4dl7lusYUXjzYUG4,16564 +sqlalchemy/dialects/postgresql/hstore.py,sha256=eRARNnn2-izprXiKQuv07ZzVAt4xNDOH3yt2_3GTYRE,12675 +sqlalchemy/dialects/postgresql/json.py,sha256=i10iOhgVu8JeBvIRiq2pGJzEz1PPA60m-zRTPiv5S_8,12712 +sqlalchemy/dialects/postgresql/named_types.py,sha256=8rJ4OIYlYBTSxHQA53exfcjrpyxjqFkReGn57rco6M8,17464 +sqlalchemy/dialects/postgresql/pg8000.py,sha256=nn8WKHstnCtQdf46-3ErH9HaaR0rQTFcZM9NAg_Xxgw,16187 +sqlalchemy/dialects/postgresql/pg_catalog.py,sha256=3GTZ0vA0Yeo92Fj20zQnxQarMJdkZanlK-T_k-xMWX8,9092 +sqlalchemy/dialects/postgresql/provision.py,sha256=_sD_42mkypvAwDxwT6xeCGnHD5EMRVubIN5eonZ8MsQ,5678 +sqlalchemy/dialects/postgresql/psycopg.py,sha256=oktcz3oCHeRUHfBlPmjPNMgxdZE15KidXjqxkPPvqrE,22838 +sqlalchemy/dialects/postgresql/psycopg2.py,sha256=zcpfD1U6tBz38b-wTJFhsNFcuh4pg52LNKUFOpBbDWA,31530 +sqlalchemy/dialects/postgresql/psycopg2cffi.py,sha256=gITk63w4Gi4wXQxBW22a0VGVUg-oBMyfg_YgIHc5kww,1800 +sqlalchemy/dialects/postgresql/ranges.py,sha256=BXRjFppTWxT3Vpg1YeZaQ6BnR3z1C659-x59aJEUBbY,31655 +sqlalchemy/dialects/postgresql/types.py,sha256=a64FWSpouoLLSEzIDTaLoefA4T5NpwYNmzfWnUhzrA4,6992 +sqlalchemy/dialects/sqlite/__init__.py,sha256=CHJgBNgr7eufrgF-0l27xohu4N317u1IOy7Hyyrxx0o,1230 +sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/aiosqlite.cpython-311.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/base.cpython-311.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/dml.cpython-311.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/json.cpython-311.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/provision.cpython-311.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/pysqlcipher.cpython-311.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-311.pyc,, +sqlalchemy/dialects/sqlite/aiosqlite.py,sha256=ICrVw2_Q3_VCHkNRVaz-1_gskkQxMNcUmvFnXUnvDpQ,11107 +sqlalchemy/dialects/sqlite/base.py,sha256=6tAfT8wkg4TVIIoOqA255I8M1HSIUkkxhFk2ftXJHR4,98993 +sqlalchemy/dialects/sqlite/dml.py,sha256=oHPSCTLNec6NgiK7dcNVOpG-mbLuz2h5b7yYayMt1dM,7702 +sqlalchemy/dialects/sqlite/json.py,sha256=IZR_pBgC9sWLtP5SXm-o5FR6SScGLi4DEMGbLJzWN8E,2619 +sqlalchemy/dialects/sqlite/provision.py,sha256=2LNwUT3zftd3WeGBJ9UsVKtwXn38KEdDxwZaJ2WXNjM,5575 +sqlalchemy/dialects/sqlite/pysqlcipher.py,sha256=F8y3R0dILJcmqUzHotYF4tLUppe3PSU_C7Xdqm4YV0o,5502 +sqlalchemy/dialects/sqlite/pysqlite.py,sha256=C7QEsd-2IWZQCIvGLxsQUcIk5TtPUFIGwalbFHIMMeo,28646 +sqlalchemy/dialects/type_migration_guidelines.txt,sha256=gyh3JCauAIFi_9XEfqm3vYv_jb2Eqcz2HjpmC9ZEPMM,8384 +sqlalchemy/engine/__init__.py,sha256=ZlB1LVIV2GjvwyvKm2W0qVYQf51g8AiQvTkHGb1C8A0,2880 +sqlalchemy/engine/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/_py_processors.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/_py_row.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/_py_util.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/base.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/characteristics.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/create.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/cursor.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/default.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/events.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/interfaces.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/mock.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/processors.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/reflection.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/result.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/row.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/strategies.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/url.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/util.cpython-311.pyc,, +sqlalchemy/engine/_py_processors.py,sha256=XuNIr2kzSay7mAWy14Aq1q2H3ZcineWY-ERfy0yvWpw,3880 +sqlalchemy/engine/_py_row.py,sha256=WASkBfwldq9LApfe1ILn93amhSc0ReihKic2lLO0gxI,3671 +sqlalchemy/engine/_py_util.py,sha256=HB-18ta-qhMrA1oNIDeobt4TtyqLUTzbfRlkN6elRb0,2313 +sqlalchemy/engine/base.py,sha256=vizXH9ZMRvdK_-PsOkO-mMDQV6zn8iZHoWX1RLbL2MQ,125328 +sqlalchemy/engine/characteristics.py,sha256=P7JlS02X1DKRSpgqpQPwt2sFsatm1L1hVxdvvw3u95s,2419 +sqlalchemy/engine/create.py,sha256=8NYKzg_mKhRbvCY--pHMh4nzH2FhruMvrKyHqvB0L1Q,33491 +sqlalchemy/engine/cursor.py,sha256=N1CU5ZGDGKcqSfAqUgAkG_6Mqlr4vNvMc_GTZJz2PaY,76557 +sqlalchemy/engine/default.py,sha256=7UwBsXKR_TEYk6W-d-GH7-6ggMWwyaJTcMrnBz_I5jQ,85684 +sqlalchemy/engine/events.py,sha256=6bfLIn6p0IDy0bnJ54JgVmZxIT736SqUHxL4p3e0_jM,38377 +sqlalchemy/engine/interfaces.py,sha256=DlLCINg-KPKjjJJcTf1ISWGaxKWpw9KSJE8c8OHIc_Q,116238 +sqlalchemy/engine/mock.py,sha256=SfOLxXvqaeFdS4MzmGyreGhfP8yatuEqIW67uTPkCIg,4306 +sqlalchemy/engine/processors.py,sha256=GvY0nS06PrGMwgwk4HHYX8QGvIUA0vEaNAmuov08BiY,2444 +sqlalchemy/engine/reflection.py,sha256=2b-ik1EXrjd5yOFRVxkRIHfItmE4MYDzHiVv--A0l0M,77220 +sqlalchemy/engine/result.py,sha256=WEjiQ6B-S4PVmIVDcFdpjfI7LjLGHgIud6fKRJZbSaw,80126 +sqlalchemy/engine/row.py,sha256=bWGDwmdXkL9YzG0hb3M2oiasJntFlYtuMW26dA6akcU,10817 +sqlalchemy/engine/strategies.py,sha256=Ryy15JovfbIMsF2sM23z0HYJ_7lXRBQlzpLacbn0mLg,461 +sqlalchemy/engine/url.py,sha256=UlNF1rFrc5eCU7WpTNy3Vqd0bJ_YB78a_nSquTSx-mY,31361 +sqlalchemy/engine/util.py,sha256=YSuXV8ngYMaQy7mouAFJiin-rrtD6Pm04KZiIfM-sTs,5849 +sqlalchemy/event/__init__.py,sha256=2QcWKXnqGRkl0lroK7ei8jT2Qbt8SRn_jqlTuYXGLu0,1022 +sqlalchemy/event/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/event/__pycache__/api.cpython-311.pyc,, +sqlalchemy/event/__pycache__/attr.cpython-311.pyc,, +sqlalchemy/event/__pycache__/base.cpython-311.pyc,, +sqlalchemy/event/__pycache__/legacy.cpython-311.pyc,, +sqlalchemy/event/__pycache__/registry.cpython-311.pyc,, +sqlalchemy/event/api.py,sha256=_TjSW28so8R84M_s7gV6oMlgpvZ0MuM0fNxWEMj4BGM,8452 +sqlalchemy/event/attr.py,sha256=o-Vr3RAGxE2mCXIvlMAGWmdb4My6q-JPkNTQdCW3IpI,21079 +sqlalchemy/event/base.py,sha256=366mOyi7uNRaniZuMuMZwlr13pbmyLFq4ds7JlOFEm4,15462 +sqlalchemy/event/legacy.py,sha256=V0Uv8kM0x_Yteik3oxy8JrZfvUmlkVN7cNkbAosV9kw,8459 +sqlalchemy/event/registry.py,sha256=0hWOxWeadXBr2YH1MhV7beeqlpXNkWycQJ2ZhpWjBHs,11249 +sqlalchemy/events.py,sha256=T8_TlVzRzd0Af9AAKUPXPxROwxeux7KuNhHTG0Cxamg,553 +sqlalchemy/exc.py,sha256=qAEWjEGvoPvEdzLalZfqWSCr7D1OUh1LikZPie0Ld3s,24844 +sqlalchemy/ext/__init__.py,sha256=2ow4CHEH4B_6wyAWKh1wqEbAUXG5ia2z2zASTa0Oqdk,333 +sqlalchemy/ext/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/associationproxy.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/automap.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/baked.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/compiler.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/horizontal_shard.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/hybrid.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/indexable.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/instrumentation.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/mutable.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/orderinglist.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/serializer.cpython-311.pyc,, +sqlalchemy/ext/associationproxy.py,sha256=hPg0HqAPHsYksZASZBVqZ9zOaCp9Ts2NXk4YF6At0QI,66984 +sqlalchemy/ext/asyncio/__init__.py,sha256=Qh5SCnlKUSkm1Ko5mzlNZ3_BUuU-aFg0vnlkhEOJdOE,1279 +sqlalchemy/ext/asyncio/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/ext/asyncio/__pycache__/base.cpython-311.pyc,, +sqlalchemy/ext/asyncio/__pycache__/engine.cpython-311.pyc,, +sqlalchemy/ext/asyncio/__pycache__/exc.cpython-311.pyc,, +sqlalchemy/ext/asyncio/__pycache__/result.cpython-311.pyc,, +sqlalchemy/ext/asyncio/__pycache__/scoping.cpython-311.pyc,, +sqlalchemy/ext/asyncio/__pycache__/session.cpython-311.pyc,, +sqlalchemy/ext/asyncio/base.py,sha256=_7X38UUqpiTrSpp1Sz8jspjb7ELH7Uq2gSgJD1u27Vg,9294 +sqlalchemy/ext/asyncio/engine.py,sha256=GpStpMTXY_F7oC-UQMMUsbBfkFKp9QcjiF5cKVxe7xo,47435 +sqlalchemy/ext/asyncio/exc.py,sha256=AeGYi7BtwZGHv4ZWaJl7wzE4u8dRlzi_06V_ipNPdfU,660 +sqlalchemy/ext/asyncio/result.py,sha256=DrGcMICQThnvVH3YabnERYWONrQ3-E1oM-oVrSFT66E,31546 +sqlalchemy/ext/asyncio/scoping.py,sha256=J9GQ9g3sj4g5gVk2cHzFHuR6u1Bq5izWH3vBu9sWFtc,51073 +sqlalchemy/ext/asyncio/session.py,sha256=v1DukTyHJhRyG3S4LNgG7oJf1GLq3-spk-BvAD8fgX0,61625 +sqlalchemy/ext/automap.py,sha256=jovTY20R8rwQZVZ9byEcwFDmTe65dCXxLUk4vDLS5mU,63093 +sqlalchemy/ext/baked.py,sha256=vHWGGYyceArr5v-nGxgDfwVgnvUjcuGOllAZ5zb_PXI,18392 +sqlalchemy/ext/compiler.py,sha256=pno-btbT4t16LEHUkRyVX5K6ct-MsPfixO41jhUI6R4,20946 +sqlalchemy/ext/declarative/__init__.py,sha256=4a8Wl2P_BqYVYmx-HsPtt_U-NvwpVsAKtfWUSNbA2uY,1883 +sqlalchemy/ext/declarative/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/ext/declarative/__pycache__/extensions.cpython-311.pyc,, +sqlalchemy/ext/declarative/extensions.py,sha256=5GnWuX0HWsiX4V2feZAPRvbgqpdLo7Nxm07spw4y-N4,19086 +sqlalchemy/ext/horizontal_shard.py,sha256=xv0tH4hKzSl0-fYRfh3uwe109v85Y8of5fcXmqCMbUA,17251 +sqlalchemy/ext/hybrid.py,sha256=3Zj6VBzzfi13gnBbKMfkt2TY_1EEXBmZ-d4ZAybFV50,54053 +sqlalchemy/ext/indexable.py,sha256=F3NC4VaUkhrx4jDmaEuJLQ2AXatk9l4l_aVI5Uzazbs,11369 +sqlalchemy/ext/instrumentation.py,sha256=biLs17X8UIGzisx-jC6JOphtldi-mlfR2bfumnlar70,16175 +sqlalchemy/ext/mutable.py,sha256=3s_qKPt6It7A-7gdQxjL5p7kFE72raf0lgjimK__lFk,38471 +sqlalchemy/ext/mypy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +sqlalchemy/ext/mypy/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/ext/mypy/__pycache__/apply.cpython-311.pyc,, +sqlalchemy/ext/mypy/__pycache__/decl_class.cpython-311.pyc,, +sqlalchemy/ext/mypy/__pycache__/infer.cpython-311.pyc,, +sqlalchemy/ext/mypy/__pycache__/names.cpython-311.pyc,, +sqlalchemy/ext/mypy/__pycache__/plugin.cpython-311.pyc,, +sqlalchemy/ext/mypy/__pycache__/util.cpython-311.pyc,, +sqlalchemy/ext/mypy/apply.py,sha256=4YMDgNNrmJCVXBbW59gVe0y1vAvvlqdazwoNS2DtXjA,10825 +sqlalchemy/ext/mypy/decl_class.py,sha256=zbfCftZkn7lYxd88NuVgBb4euHsgrNLc5tw4iwpSrlA,17898 +sqlalchemy/ext/mypy/infer.py,sha256=n9h0JUHo-ZQwI3Zb-Gu-zM4KprQuVlPslVax6-0yYMk,19959 +sqlalchemy/ext/mypy/names.py,sha256=syJhY2UYcodS_NjuNdg-7ay_ZW8kf6xXMbTpMjHrdLQ,11310 +sqlalchemy/ext/mypy/plugin.py,sha256=lLYMa5c1T3aOkqzBhF1AqxunAII6-JUYNxO7girK0Jw,10055 +sqlalchemy/ext/mypy/util.py,sha256=FfcCXJ8K1m5FLBFE5LO-PRPUwAji0HRJuIuvC3IrrpE,9307 +sqlalchemy/ext/orderinglist.py,sha256=xeonIRL-m5Y4vB2n_1Nab8B61geRLHR0kyC_KnXTS7k,14800 +sqlalchemy/ext/serializer.py,sha256=BhyC7ydKcKKz4vlxyU_8ranVigiGSO1hw_LieCxLCgM,6363 +sqlalchemy/future/__init__.py,sha256=Iio4lD-SrIcuBq0gP7MRgVnU4v36gIMLHiQrSKy-sPM,532 +sqlalchemy/future/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/future/__pycache__/engine.cpython-311.pyc,, +sqlalchemy/future/engine.py,sha256=4iO5THuQWIy3UGpOOMml23daun4wHdRZ6JVSwWykjJI,514 +sqlalchemy/inspection.py,sha256=YXzepqym7pHHZPJVeMrR2-ahVHJRGMDyew7V9MIg61o,4576 +sqlalchemy/log.py,sha256=_y9novClgwjLqw40-LYIIwl51Bq1D6Z6-XzaK4ib2v0,8920 +sqlalchemy/orm/__init__.py,sha256=IlYtCsaaav9KrTWhqoTsbhL-wXHIV_FAZbOlO7ajDs8,8635 +sqlalchemy/orm/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/_orm_constructors.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/_typing.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/attributes.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/base.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/bulk_persistence.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/clsregistry.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/collections.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/context.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/decl_api.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/decl_base.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/dependency.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/descriptor_props.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/dynamic.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/evaluator.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/events.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/exc.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/identity.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/instrumentation.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/interfaces.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/loading.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/mapped_collection.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/mapper.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/path_registry.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/persistence.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/properties.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/query.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/relationships.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/scoping.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/session.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/state.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/state_changes.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/strategies.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/strategy_options.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/sync.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/unitofwork.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/util.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/writeonly.cpython-311.pyc,, +sqlalchemy/orm/_orm_constructors.py,sha256=Z90nxakupdiiVrL9mEPOpET1yfJdMzDWwsRTCxeO1cg,101743 +sqlalchemy/orm/_typing.py,sha256=itHJpVx5GjBgOIz-Ut6KNswQqkzJX4jaG6dgkCwbqzo,5421 +sqlalchemy/orm/attributes.py,sha256=N-7PzE_xWETTK06JF4o9ZB8cYWcezzHOiSz_hzJUEuc,94567 +sqlalchemy/orm/base.py,sha256=wKoQOjXqQTYntfgzrmBFWtcREcapxHsh9oENWx3ARTs,27762 +sqlalchemy/orm/bulk_persistence.py,sha256=sRX_Xsb8HT2UzK0Nl2axyNPV5_zdl3fVPzgZzJAiQ1o,70097 +sqlalchemy/orm/clsregistry.py,sha256=9B3ZIZbPgud4wuFIiZ4VAqNFUlJtROOcCfeDCIPdQio,18523 +sqlalchemy/orm/collections.py,sha256=IsMkk3ocG_K4OCjOKX4bVM5qqS7ICGSZ2g1T7nH-1-c,52517 +sqlalchemy/orm/context.py,sha256=bmIPeIfCrtK5TZoKqhWvO4rHr1WaVMWNjsEIlRh2gWI,112355 +sqlalchemy/orm/decl_api.py,sha256=oA9QhULZUlXAzypXt14rTzpA-Ukdit3QlqDyihp_mic,64653 +sqlalchemy/orm/decl_base.py,sha256=58tNtUxvVasQ5l05Ag2e05mMNdYiIxQ3dOcng6oB6kA,83453 +sqlalchemy/orm/dependency.py,sha256=KXs8vCs85F4CKXDR8bULv8XFctt0qUhLQFd6WjE8Rpw,48332 +sqlalchemy/orm/descriptor_props.py,sha256=XM21maTslscn5ng6dbKu1KxC6EUkhIGOzaYdrPCo0No,38506 +sqlalchemy/orm/dynamic.py,sha256=MWkalEIrgW0p_CRr5Uclt6Ak-jUvcpyYHaTWidIuXdc,8898 +sqlalchemy/orm/evaluator.py,sha256=lQ_uAoUBKJtQAyvhyFfHOf8gvxk0_-r4KpqQR53-COE,12293 +sqlalchemy/orm/events.py,sha256=bRXddn5sLh2r8wVGizVrrfd9no-rl1-_Uhw0dphXiMo,130512 +sqlalchemy/orm/exc.py,sha256=k9K4M3zZvE7877TiTOI5gG4MOgnBEbKqvAsP43JU2Dk,7583 +sqlalchemy/orm/identity.py,sha256=mVaoHHtniM1-wSqJ0VPu2v6LaSJfer4_vLsxFVw8aXc,9551 +sqlalchemy/orm/instrumentation.py,sha256=qYpEX9uscjx12TyDtd5jNcXeb2FP7SSklzwvnhvVg9U,25209 +sqlalchemy/orm/interfaces.py,sha256=6vE5TGPtG2-nZNe0lFyZbxKzb-I0FnLlojavTj7BUCg,48479 +sqlalchemy/orm/loading.py,sha256=zi5wnvXDGkfEWpN_WZDzMgXFJz0IouLsEaQRjIV1fJ8,58052 +sqlalchemy/orm/mapped_collection.py,sha256=3QZmTvaotMSyH5FiAFxWSe1peRdWo7rOb2bHjHx2hCw,19827 +sqlalchemy/orm/mapper.py,sha256=dzxPJ2EoDZWq2yLEzpJi0odqaT2RMiaO4ig8Lj5N9Wk,173800 +sqlalchemy/orm/path_registry.py,sha256=P5SuugqCBdOJogt-scjoxq_UIHBoRtIwTuZ9xBYGTM8,25284 +sqlalchemy/orm/persistence.py,sha256=JLtJnGHUQBljc0yroa1Fj4pGZQZsFjxMS-XQpUDGXe8,61752 +sqlalchemy/orm/properties.py,sha256=PYJG0BcU_AdDZdZZCsO4v7cWjdQBMvzi9KO_pDYoayA,27420 +sqlalchemy/orm/query.py,sha256=VYTv6gIksjFT6-LcdcDxX0Iw4b5nTu4pAsqIWbvohF8,121302 +sqlalchemy/orm/relationships.py,sha256=DCYezm_EY-rP1TYI1cQEctyNc4mxMdkt64_rz0JBtow,129875 +sqlalchemy/orm/scoping.py,sha256=frmeMkJgL2BOS4HOa24SenWPivaPfX-hdLOLhi_zCgw,76920 +sqlalchemy/orm/session.py,sha256=KkJWEKqZRPsyPwaI0ySqzuSeNlzSGUboj2QuVOKl96Y,191587 +sqlalchemy/orm/state.py,sha256=76y_qgBF4TrbS1Gtf7MJrH9s_YPbe_4Dcd9kEmzapAA,38369 +sqlalchemy/orm/state_changes.py,sha256=ojrZ9fdqaSAn_hLaUtINLljz-Gm4-edrDXeVK6Wyb_s,6780 +sqlalchemy/orm/strategies.py,sha256=v8QYuwf6Lm0DclQMq9Cev9v8HnJ--c7Vbpm5AJFm15c,117841 +sqlalchemy/orm/strategy_options.py,sha256=8x3_SpliYQDwniyQM8ubLhnhxfYdYPbubJ52SKGk-rg,84150 +sqlalchemy/orm/sync.py,sha256=d3hpLcBBBoM4Oyk4z0kMd_fa5AYwaGu1ZJ1O4JYX408,5914 +sqlalchemy/orm/unitofwork.py,sha256=djH2T2qv-nRgAMQFyZk88hwD8GjnJKZb4sZF4ZTJ1cQ,27833 +sqlalchemy/orm/util.py,sha256=VxgXAyQKUk5ZHt-v4qzBEBj_s8p9PKL9f7PJDgfYhM4,82120 +sqlalchemy/orm/writeonly.py,sha256=6XcL7p7mFUt4VkG20jVstmxXWd6uaftt8eDskYd825w,20158 +sqlalchemy/pool/__init__.py,sha256=rvWJtziqz1Yp_9NU7r-cKH1WKi8MwcjZX6kuBYu_s6s,1859 +sqlalchemy/pool/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/pool/__pycache__/base.cpython-311.pyc,, +sqlalchemy/pool/__pycache__/events.cpython-311.pyc,, +sqlalchemy/pool/__pycache__/impl.cpython-311.pyc,, +sqlalchemy/pool/base.py,sha256=mLuKb6HIn3VTuFSKZUivmBUNnYFMFxahbRYaUVbyZQY,53873 +sqlalchemy/pool/events.py,sha256=dQDxP7Rwz3nDv2xkxQvkq3Eyj-00sBYIoF02lrKUHLM,13571 +sqlalchemy/pool/impl.py,sha256=abSYYiBp-a_nimXlOPAh0V_3IWq4kjKTSZpxZN2e-Io,18258 +sqlalchemy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +sqlalchemy/schema.py,sha256=Liwt9G2PyOZZGfQkTGx7fFjTNH2o8t9kPcCAIHF9etw,3264 +sqlalchemy/sql/__init__.py,sha256=t_Z2MWcdZmo0zchFRaikaqomPYFPqHsWC4PkTwG8tHI,5827 +sqlalchemy/sql/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/_dml_constructors.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/_elements_constructors.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/_orm_types.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/_py_util.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/_selectable_constructors.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/_typing.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/annotation.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/base.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/cache_key.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/coercions.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/compiler.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/crud.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/ddl.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/default_comparator.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/dml.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/elements.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/events.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/expression.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/functions.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/lambdas.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/naming.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/operators.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/roles.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/schema.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/selectable.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/sqltypes.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/traversals.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/type_api.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/util.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/visitors.cpython-311.pyc,, +sqlalchemy/sql/_dml_constructors.py,sha256=CRI_cxOwcSBPUhouMuNoxBVb3EB0b6zQo6YSjI1d2Vo,4007 +sqlalchemy/sql/_elements_constructors.py,sha256=zXFHjCkXu1Mm_yyhZvIiDplLo5hfy1iQ4SxNKk-HxL4,62921 +sqlalchemy/sql/_orm_types.py,sha256=WIdXTDALHCd3PuzpAPot2psv505T817wnQ3oXuGH7CU,640 +sqlalchemy/sql/_py_util.py,sha256=7BczrMrjQGEF5_V1brW0V6Gj1gqVxCfzxifNJ9qiFu4,2250 +sqlalchemy/sql/_selectable_constructors.py,sha256=kHsJViBwydt3l-aiqtI2yLK4BgjEsVB9lpKPuWSWv60,19454 +sqlalchemy/sql/_typing.py,sha256=OthFis7vrntNb-iQ9PK-ZRWzYt_15PepgVuF0V9KrUw,10835 +sqlalchemy/sql/annotation.py,sha256=R9LbjSTxl5i9WFdCGGWm--TDtLsUTl4fNBryZcMdvZw,18203 +sqlalchemy/sql/base.py,sha256=TSn8UEKBdyGVUNi8q-2aOcR3p0_WOFQQSBI8zH9h9PQ,75954 +sqlalchemy/sql/cache_key.py,sha256=aHixtNULOyGHdPxhcPkdj6kZjRSVq-SmVFGLxXtIGUI,33686 +sqlalchemy/sql/coercions.py,sha256=dkw-O3oszb_W1PRG60jGbAJzjxgMbJ0wKXXnMXxk_xM,41898 +sqlalchemy/sql/compiler.py,sha256=KVbc45eTrGhhrKRE_XIQ2LbJE11LHsKh4S0Vh8MZVnE,274303 +sqlalchemy/sql/crud.py,sha256=PRH2bSLXDwWnsu57rtEAkj6yLFzWYmjAfvv80KSQf-4,57311 +sqlalchemy/sql/ddl.py,sha256=faO8swGbRea1VsooUl3l7t_aw_nsuk6GCC-qBoRic5I,47077 +sqlalchemy/sql/default_comparator.py,sha256=Z2BoFxhI02iIwVAw_yZzOhZXxSyq2o3hjqimn4V1pw4,17298 +sqlalchemy/sql/dml.py,sha256=lIyVoFJtW0Mm4mq9Bhjx1iyVpnwtdQefrBkYpupUtQU,67358 +sqlalchemy/sql/elements.py,sha256=Bx7j2zRkLi6VS_sDWhAFzvo5N8h6Yt_fezwMsUI9Mso,174164 +sqlalchemy/sql/events.py,sha256=ELMw8mkKUvVVeb354hfD_9Fk-KSX28hCfNdnMgnv2zI,18756 +sqlalchemy/sql/expression.py,sha256=QyaQIr5X6jFe8EF2smYxZ4FWPV7j-QrVevPiuyXWfi8,7648 +sqlalchemy/sql/functions.py,sha256=DvSrxyanUpi1HjCz0qgqIZzO-JnrmH7j3Vu_ZDF1O10,56293 +sqlalchemy/sql/lambdas.py,sha256=RpkziKSJbOg4he4Gn7aJsKVexCCsjKfSXC_YTeC0-PA,50765 +sqlalchemy/sql/naming.py,sha256=AwAssUZ8o0ATukD3UYO_Qecbu9y-F2krONlOo0fvBow,7079 +sqlalchemy/sql/operators.py,sha256=_6SrRxq4ZnD44Rw87ko4FEEf7ZUmPvPYwAYE2Xir2ZM,76526 +sqlalchemy/sql/roles.py,sha256=Rkbx36tMWkq6uu6bl1DMDkLQY8VFpKZtqfmYxooE8MQ,7952 +sqlalchemy/sql/schema.py,sha256=fGAm4FcjNTFs8931HSCRsnaFD-z1SWa_kDXmGQwo5J4,233090 +sqlalchemy/sql/selectable.py,sha256=kucSvlsl4QaU1Suym6tBsJtQGUUry1Vz9XRNWyN6HMs,238961 +sqlalchemy/sql/sqltypes.py,sha256=OTqoxmcw55d9esiuwEs2cYjk69D4hzQYcCwNHjaNwVg,129432 +sqlalchemy/sql/traversals.py,sha256=s7BwwijJnnG_x_BnID3DiOYqol9LY6rw5nECSEY0TRo,34628 +sqlalchemy/sql/type_api.py,sha256=qntuAED2iX7eAMrlH_Bx2_74ELl9sYEgaPP5insrHaU,87457 +sqlalchemy/sql/util.py,sha256=5UCudam-vT7lMoYKv2juS483vjdiY2kcFejfjk17KlI,49770 +sqlalchemy/sql/visitors.py,sha256=n_VlVekbAdHgc4gYvvwHpXowWOPUX5ETuP4Bkdkww2Q,37536 +sqlalchemy/testing/__init__.py,sha256=I_4C9vgF-GRODJ_IRNxIXXSQHgUDNVggGFFv6v0BJBQ,3221 +sqlalchemy/testing/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/assertions.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/assertsql.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/asyncio.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/config.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/engines.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/entities.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/exclusions.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/fixtures.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/pickleable.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/profiling.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/provision.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/requirements.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/schema.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/util.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/warnings.cpython-311.pyc,, +sqlalchemy/testing/assertions.py,sha256=K_wIe570kI6xbtZmWMnLiuhBaCFyoQx-iaau9CR1PLI,32428 +sqlalchemy/testing/assertsql.py,sha256=0Rjop10fQbscc7I09pAsgszUxOm9pTyzrTdeSr24anA,17294 +sqlalchemy/testing/asyncio.py,sha256=JQM4Ju4xdDqz0Mt9XZjlGI-q6W5tyTeTU39MVk6Qj8g,3860 +sqlalchemy/testing/config.py,sha256=iJ_z8tVYjV1nBsweG24tEALdjLoM1MvIxRdt9e1Vu7w,11362 +sqlalchemy/testing/engines.py,sha256=nFeIIoMPdXRZ6fRkeem6NbxrD7YIr6c76O3jSoJ9GQE,13826 +sqlalchemy/testing/entities.py,sha256=E7IkhsQaziZSOZkKkFnfUvB0165SH5MP1q4QkGKdf98,3471 +sqlalchemy/testing/exclusions.py,sha256=rWyo1SZpZ-EjNkvr-O085A3XSAqxSL5uqgOE4L5mzM0,12879 +sqlalchemy/testing/fixtures.py,sha256=s3-wyLuigro8bFORv6EyBLzMAUnr4BGlEhYAPsz1ljQ,34164 +sqlalchemy/testing/pickleable.py,sha256=_JmUGGI8f2h00tFqlxybOWR57v2gGD7WdgaPHVkYH3M,3044 +sqlalchemy/testing/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +sqlalchemy/testing/plugin/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/testing/plugin/__pycache__/bootstrap.cpython-311.pyc,, +sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-311.pyc,, +sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-311.pyc,, +sqlalchemy/testing/plugin/bootstrap.py,sha256=3WkvZXQad0oyxg6nJyLEthN30zBuueB33LFxWeMBdKc,1482 +sqlalchemy/testing/plugin/plugin_base.py,sha256=3JudFkMre2rqiakpg53fPGXrRy5AG78txcb5W08QbBs,22059 +sqlalchemy/testing/plugin/pytestplugin.py,sha256=Zw3SD9SGROuK4Lune9MHBEkGN3KExZSl5vaMTj8AwNE,28094 +sqlalchemy/testing/profiling.py,sha256=W8EgAsH3tLE3inRTiaAiSr0R2Nk4U-ox06Oq_dhIz3w,10478 +sqlalchemy/testing/provision.py,sha256=UNBHe7uj5qmEgk8n_T64kXx8B0GNQ1JwX4W35gzKbR8,14692 +sqlalchemy/testing/requirements.py,sha256=XEZDN62TZbhJwOewKIlZteMbx09G9a5qj4zWTQVxKrM,52452 +sqlalchemy/testing/schema.py,sha256=OMPF_3L_7WAdpdSF2Id1h2QUBFMJdg9SfkFBlAWPBPM,6739 +sqlalchemy/testing/suite/__init__.py,sha256=u3lEc0j47s7Dad_2SVWOZ6EU2aOMRWqE_WrQ17HmBsA,489 +sqlalchemy/testing/suite/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_cte.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_deprecations.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_dialect.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_insert.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_results.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_rowcount.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_select.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_types.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_unicode_ddl.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-311.pyc,, +sqlalchemy/testing/suite/test_cte.py,sha256=9IKM7tzQgPiopqk7Xm-CgnUrj0Rot7FUa8er0DTlPfM,6412 +sqlalchemy/testing/suite/test_ddl.py,sha256=VQuejaNUMN484DxwkYL57ZEnPY5UhNGWkQVgquPrWHA,12168 +sqlalchemy/testing/suite/test_deprecations.py,sha256=8mhjZyrECXiVyE88BJLbyj4Jz_niXOs6ZOXd9rFAWsk,5229 +sqlalchemy/testing/suite/test_dialect.py,sha256=vh2zRKZ0T45vybOK50eKlTkkZJlpCPwGnHfHW44EL4k,21707 +sqlalchemy/testing/suite/test_insert.py,sha256=V6V7yKCaAJWUWKqKh_yCGfPgH1Zu_T_hmqk80Sisa5E,15328 +sqlalchemy/testing/suite/test_reflection.py,sha256=Le0Jn6AUXwJGil9ghyr9MhGR-rfZc1S7g4wlVIcqutI,107556 +sqlalchemy/testing/suite/test_results.py,sha256=S5abSSSY4ZxVjueiq_0R5VFAAB7KxO0b23QFMFPm26k,16129 +sqlalchemy/testing/suite/test_rowcount.py,sha256=ID2Y1jDZ1MjQyZldWQPt40qD2eu0haTaYB2AdWQ1Nnk,6356 +sqlalchemy/testing/suite/test_select.py,sha256=FQhwUKZfl6NgHVE44IVTwAlloyVDBkT1LMkBwTtCwBw,60209 +sqlalchemy/testing/suite/test_sequence.py,sha256=K5fSDo_GpuBCc-YKGZK4tHvcUmoZuhuJRKdmv7PGe8Y,9985 +sqlalchemy/testing/suite/test_types.py,sha256=QiG-3HbVr-WEgzysY2pHssGK2QQM8vY6tSGf_EYL2TQ,65488 +sqlalchemy/testing/suite/test_unicode_ddl.py,sha256=1n0xf7EyGuLYIMiwc5lANGWvCrmoXf3gtQM93sMcd3c,6070 +sqlalchemy/testing/suite/test_update_delete.py,sha256=cj9C7U8MFxMSfdckAdODQHsnqwOtU112zqk5U8iyCTM,1710 +sqlalchemy/testing/util.py,sha256=fzcrcrabCcCcYh57f8fS-X4ZZy7wIVcySkw5yKKiR5Q,14688 +sqlalchemy/testing/warnings.py,sha256=ymXClxi_YtysQJZZQzgjT-d3tW63z4pOfKJsTqaBLMQ,1598 +sqlalchemy/types.py,sha256=bV5WvXIjsG-bWRcwCVACJ6m3tlSMS5XNdtXVXGTMeI8,3244 +sqlalchemy/util/__init__.py,sha256=QxB-49lOQh4SjC6tIhx5bXQr9dbduK27sa3l9F7L5zA,8366 +sqlalchemy/util/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/util/__pycache__/_collections.cpython-311.pyc,, +sqlalchemy/util/__pycache__/_concurrency_py3k.cpython-311.pyc,, +sqlalchemy/util/__pycache__/_has_cy.cpython-311.pyc,, +sqlalchemy/util/__pycache__/_py_collections.cpython-311.pyc,, +sqlalchemy/util/__pycache__/compat.cpython-311.pyc,, +sqlalchemy/util/__pycache__/concurrency.cpython-311.pyc,, +sqlalchemy/util/__pycache__/deprecations.cpython-311.pyc,, +sqlalchemy/util/__pycache__/langhelpers.cpython-311.pyc,, +sqlalchemy/util/__pycache__/preloaded.cpython-311.pyc,, +sqlalchemy/util/__pycache__/queue.cpython-311.pyc,, +sqlalchemy/util/__pycache__/tool_support.cpython-311.pyc,, +sqlalchemy/util/__pycache__/topological.cpython-311.pyc,, +sqlalchemy/util/__pycache__/typing.cpython-311.pyc,, +sqlalchemy/util/_collections.py,sha256=yUsrZu5aQh0lK_ht3540KXsoaM-lz4nqK1gHXx29lBc,21124 +sqlalchemy/util/_concurrency_py3k.py,sha256=EHhA2yZnpSGy6MZOCySgImLf4W_7NNSNMemQAZyO_gM,8460 +sqlalchemy/util/_has_cy.py,sha256=7V8ZfMrlED0bIc6DWsBC_lTEP1JEihWKPdjyLJtxfaE,1268 +sqlalchemy/util/_py_collections.py,sha256=lwf6V7hnvqP_88eVKZa6GqshDxyBkhPczaIhpfrXE-Y,17217 +sqlalchemy/util/compat.py,sha256=-bFeDV6z1cDWXdovaFg6ZS39VTaVCiVFTJ2YcO21OEQ,8657 +sqlalchemy/util/concurrency.py,sha256=rLb4LbPSTnGaSb381_e3VwHbEjqiF10lkarFjihywTY,2353 +sqlalchemy/util/deprecations.py,sha256=TmpMv6GGFu7hofJwWzhoi8leF_XzWL7TL-QIF7qGPQs,12520 +sqlalchemy/util/langhelpers.py,sha256=eA3qLH3xVEZWA53UHhIERzG3uMj3UEIiNrz7UfE2nyI,67149 +sqlalchemy/util/preloaded.py,sha256=tMuj_6GELLQj1I8YRAKu--VLnxI9kH8Si_IwlDfre4M,6055 +sqlalchemy/util/queue.py,sha256=-DPCfkQgtqP9znBvm3bRdYjAWs4dysflpL805IMf22A,10529 +sqlalchemy/util/tool_support.py,sha256=SOfhWXzZXqx5RYX9WM_CeBJGGgV0eaxpv96VFb5KEKs,6167 +sqlalchemy/util/topological.py,sha256=fV2yAwoCzeeaib8GXt_iITn5JHarBUGEhfZLfZSSjsc,3580 +sqlalchemy/util/typing.py,sha256=CE1gYopMyfJXFpEfp6dCLf72gb8PxyiugbRochNVX1g,16209 diff --git a/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/REQUESTED b/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/REQUESTED new file mode 100644 index 000000000..e69de29bb diff --git a/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/WHEEL b/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/WHEEL new file mode 100644 index 000000000..30c3ff1eb --- /dev/null +++ b/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.40.0) +Root-Is-Purelib: false +Tag: cp311-cp311-win_amd64 + diff --git a/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/top_level.txt b/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/top_level.txt new file mode 100644 index 000000000..39fb2befb --- /dev/null +++ b/.venv/Lib/site-packages/SQLAlchemy-2.0.13.dist-info/top_level.txt @@ -0,0 +1 @@ +sqlalchemy diff --git a/.venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/INSTALLER b/.venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/.venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/LICENSE.rst b/.venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/LICENSE.rst new file mode 100644 index 000000000..c37cae49e --- /dev/null +++ b/.venv/Lib/site-packages/Werkzeug-2.3.4.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/.venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/METADATA b/.venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/METADATA new file mode 100644 index 000000000..3b5817020 --- /dev/null +++ b/.venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/METADATA @@ -0,0 +1,120 @@ +Metadata-Version: 2.1 +Name: Werkzeug +Version: 2.3.4 +Summary: The comprehensive WSGI web application library. +Author-email: Armin Ronacher +Maintainer-email: Pallets +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: Chat, https://discord.gg/pallets +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware +Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Requires-Python: >=3.8 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst +Requires-Dist: MarkupSafe (>=2.1.1) +Provides-Extra: watchdog +Requires-Dist: watchdog (>=2.3) ; 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/ +- Chat: https://discord.gg/pallets diff --git a/.venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/RECORD b/.venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/RECORD new file mode 100644 index 000000000..277dca0e1 --- /dev/null +++ b/.venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/RECORD @@ -0,0 +1,126 @@ +Werkzeug-2.3.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Werkzeug-2.3.4.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 +Werkzeug-2.3.4.dist-info/METADATA,sha256=8ifMq_FpMEho-Zr1j9s9tprMjSxOSdR85Y1yKaWnLDY,4205 +Werkzeug-2.3.4.dist-info/RECORD,, +Werkzeug-2.3.4.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92 +Werkzeug-2.3.4.dist-info/top_level.txt,sha256=QRyj2VjwJoQkrwjwFIOlB8Xg3r9un0NtqVHQF-15xaw,9 +werkzeug/__init__.py,sha256=NjiycImCiZEpbqEtSayxv0JB4onVuyRHYUn-NItvf6g,188 +werkzeug/__pycache__/__init__.cpython-311.pyc,, +werkzeug/__pycache__/_internal.cpython-311.pyc,, +werkzeug/__pycache__/_reloader.cpython-311.pyc,, +werkzeug/__pycache__/exceptions.cpython-311.pyc,, +werkzeug/__pycache__/formparser.cpython-311.pyc,, +werkzeug/__pycache__/http.cpython-311.pyc,, +werkzeug/__pycache__/local.cpython-311.pyc,, +werkzeug/__pycache__/security.cpython-311.pyc,, +werkzeug/__pycache__/serving.cpython-311.pyc,, +werkzeug/__pycache__/test.cpython-311.pyc,, +werkzeug/__pycache__/testapp.cpython-311.pyc,, +werkzeug/__pycache__/urls.cpython-311.pyc,, +werkzeug/__pycache__/user_agent.cpython-311.pyc,, +werkzeug/__pycache__/utils.cpython-311.pyc,, +werkzeug/__pycache__/wsgi.cpython-311.pyc,, +werkzeug/_internal.py,sha256=10weRWsedmoDrJUvS4MkCe-VsOkwbAU9PxY4-J3nOXE,7830 +werkzeug/_reloader.py,sha256=1O1DDWlqVwYIX8kgJwH5B4a_Uh6acQnw3sQf01JpXtM,14745 +werkzeug/datastructures/__init__.py,sha256=yzBdOT9DdK3nraNG49pA3bVsvtPPLx2-t2N8ZmuAd9w,1900 +werkzeug/datastructures/__pycache__/__init__.cpython-311.pyc,, +werkzeug/datastructures/__pycache__/accept.cpython-311.pyc,, +werkzeug/datastructures/__pycache__/auth.cpython-311.pyc,, +werkzeug/datastructures/__pycache__/cache_control.cpython-311.pyc,, +werkzeug/datastructures/__pycache__/csp.cpython-311.pyc,, +werkzeug/datastructures/__pycache__/etag.cpython-311.pyc,, +werkzeug/datastructures/__pycache__/file_storage.cpython-311.pyc,, +werkzeug/datastructures/__pycache__/headers.cpython-311.pyc,, +werkzeug/datastructures/__pycache__/mixins.cpython-311.pyc,, +werkzeug/datastructures/__pycache__/range.cpython-311.pyc,, +werkzeug/datastructures/__pycache__/structures.cpython-311.pyc,, +werkzeug/datastructures/accept.py,sha256=CuCvBAxNzbt4QUb17rH986vvOVGURFUjo0DX2PQy_yI,10670 +werkzeug/datastructures/accept.pyi,sha256=6P114gncjZoy-i_n_3OQy2nJVwjEAIe7PcBxKYqCEfc,1917 +werkzeug/datastructures/auth.py,sha256=JTUS67MZ4ap-C4eBXxeAwgaTr-SMqbRaLTtk_Smjo4w,16015 +werkzeug/datastructures/cache_control.py,sha256=RTUipZev50s-1TAn2rYGZrytm_6IOIxQd67fkR5bNF0,6043 +werkzeug/datastructures/cache_control.pyi,sha256=6Q93jRysAKMPWRA72OMksyn7d3ZysuxwGlHp_iwF9pA,3756 +werkzeug/datastructures/csp.py,sha256=DAOAO266LK0JKbvlG80bbkAgfrNsnU9HBoz-FdIYNdo,3244 +werkzeug/datastructures/csp.pyi,sha256=AmDWiZU4rrJA4SZmyMNI1L5PLdIfJsI5Li9r5lE1q6M,5765 +werkzeug/datastructures/etag.py,sha256=JsyI-yXayF-hQu26MyFzbHFIZsaQ6odj3RZO_jF-_cc,2913 +werkzeug/datastructures/etag.pyi,sha256=N9cuUBrZnxHmsbW0BBmjKW-djNY7WKbI6t_WopB8Zo0,1047 +werkzeug/datastructures/file_storage.py,sha256=d3E8riRUr2a9fbfXMIIJ57HeEEkWVMy6R4RKHRtu73I,6076 +werkzeug/datastructures/file_storage.pyi,sha256=2sdbKHhvbQF5FjrJuO6l_m1yZvZ4oPCUTspmdmjQlSU,1433 +werkzeug/datastructures/headers.py,sha256=V08N4VTcaA11fRq1WK5v28QomGd-A1S9CmiwugixhWo,18882 +werkzeug/datastructures/headers.pyi,sha256=66Gh9DbD8QNpLRBOuer4DMCj12csddHrcgxiJPLE5n8,4237 +werkzeug/datastructures/mixins.py,sha256=-IQSQ70UOMQlqtJEIyyhplOd4obaTOfzGvka-cunCtM,5337 +werkzeug/datastructures/mixins.pyi,sha256=y92tClxVslJBEGgAwDRsQLExfin2p0x7NfnP_b8w6xc,4191 +werkzeug/datastructures/range.py,sha256=JXSDPseG7iH5giJp3R1SnQC_SqQp634M8Iv6QTsbTxM,5669 +werkzeug/datastructures/range.pyi,sha256=bsM61iNp86gT2lyN0F_Dqg8xsnfPerdmElipuHppiJQ,1792 +werkzeug/datastructures/structures.py,sha256=_bhAf0adEk6WU2uy8jdmuxFMTFcuClY1p7jQ-3wYXj4,31761 +werkzeug/datastructures/structures.pyi,sha256=MRg-RubT3UPjh62i9-7Xht8DVL0zTApRzjs52Hfz_j4,8148 +werkzeug/debug/__init__.py,sha256=0nIJfNC8GCjaMMDBJHwp4bgWLDI-uAYIpAoNdHiVCCc,18757 +werkzeug/debug/__pycache__/__init__.cpython-311.pyc,, +werkzeug/debug/__pycache__/console.cpython-311.pyc,, +werkzeug/debug/__pycache__/repr.cpython-311.pyc,, +werkzeug/debug/__pycache__/tbtools.cpython-311.pyc,, +werkzeug/debug/console.py,sha256=FIO8gDX2eQ1_4MtpJ4s0i2gR4fFCJZTPwhSVByF4kbo,6068 +werkzeug/debug/repr.py,sha256=ECmIpNVlCppTfCuIuEgrJVfuhr8iDqPSWeVJyxt1QOM,9328 +werkzeug/debug/shared/ICON_LICENSE.md,sha256=DhA6Y1gUl5Jwfg0NFN9Rj4VWITt8tUx0IvdGf0ux9-s,222 +werkzeug/debug/shared/console.png,sha256=bxax6RXXlvOij_KeqvSNX0ojJf83YbnZ7my-3Gx9w2A,507 +werkzeug/debug/shared/debugger.js,sha256=tg42SZs1SVmYWZ-_Fj5ELK5-FLHnGNQrei0K2By8Bw8,10521 +werkzeug/debug/shared/less.png,sha256=-4-kNRaXJSONVLahrQKUxMwXGm9R4OnZ9SxDGpHlIR4,191 +werkzeug/debug/shared/more.png,sha256=GngN7CioHQoV58rH6ojnkYi8c_qED2Aka5FO5UXrReY,200 +werkzeug/debug/shared/style.css,sha256=-xSxzUEZGw_IqlDR5iZxitNl8LQUjBM-_Y4UAvXVH8g,6078 +werkzeug/debug/tbtools.py,sha256=WyNL0RCDIi3YZGifMbs99BdmwmqQRL7zJFYZ1x_GJN4,13263 +werkzeug/exceptions.py,sha256=d6VNzGcVgLazIpfwRD8pN_d3yAJNyngBDFvlXQbR-38,26062 +werkzeug/formparser.py,sha256=P3y7VdnfmeR9CBnS60-GViTc6OX6kAC6O5Ek-icYYhM,19592 +werkzeug/http.py,sha256=VYJGN6U8tlfOcIs-qYaUoo8_C8p75FFxjJOaU38Nztg,48593 +werkzeug/local.py,sha256=zrXlO1IP3KTz310h9LSdVKMaFsJfNyXkfCYCkbvlBXQ,22075 +werkzeug/middleware/__init__.py,sha256=qfqgdT5npwG9ses3-FXQJf3aB95JYP1zchetH_T3PUw,500 +werkzeug/middleware/__pycache__/__init__.cpython-311.pyc,, +werkzeug/middleware/__pycache__/dispatcher.cpython-311.pyc,, +werkzeug/middleware/__pycache__/http_proxy.cpython-311.pyc,, +werkzeug/middleware/__pycache__/lint.cpython-311.pyc,, +werkzeug/middleware/__pycache__/profiler.cpython-311.pyc,, +werkzeug/middleware/__pycache__/proxy_fix.cpython-311.pyc,, +werkzeug/middleware/__pycache__/shared_data.cpython-311.pyc,, +werkzeug/middleware/dispatcher.py,sha256=6ltzPtDsIdLTY_T1GW6kxBJL0KZftbipa_WVdKtpVQ8,2601 +werkzeug/middleware/http_proxy.py,sha256=vsSvt84m656x3mV_Fj78y7O2eYHmurWngErTcjeiz8U,7833 +werkzeug/middleware/lint.py,sha256=6CqcwMWro1p-GRUGPgQ1n21KFnTTqc6-81CGTzpcK74,13916 +werkzeug/middleware/profiler.py,sha256=KKr8nAiF9dr9pNd3G0D3xs7mUba9gvWkyK7X9ceke70,4906 +werkzeug/middleware/proxy_fix.py,sha256=dcOOSjSok2QsSh1VSNsw-a0Vy_Jn5DunlO6PRbXBq0A,6754 +werkzeug/middleware/shared_data.py,sha256=wHbKFw2vh6aZMFcL_SwHKAk6F99QHXYEC-8npqLwGt4,9489 +werkzeug/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +werkzeug/routing/__init__.py,sha256=HpvahY7WwkLdV4Cq3Bsc3GrqNon4u6t8-vhbb9E5o00,4819 +werkzeug/routing/__pycache__/__init__.cpython-311.pyc,, +werkzeug/routing/__pycache__/converters.cpython-311.pyc,, +werkzeug/routing/__pycache__/exceptions.cpython-311.pyc,, +werkzeug/routing/__pycache__/map.cpython-311.pyc,, +werkzeug/routing/__pycache__/matcher.cpython-311.pyc,, +werkzeug/routing/__pycache__/rules.cpython-311.pyc,, +werkzeug/routing/converters.py,sha256=V8e_wMRop6WG4Kymu4pBIR8OrJl-ZUQUZlinUXfw7WE,7602 +werkzeug/routing/exceptions.py,sha256=yGZ5AUL-buHp-vK8AJbZ0bLIbSckh1UyiGKgRg4ZjaA,4698 +werkzeug/routing/map.py,sha256=Y9pR5eCm8zKVEJAmqbg_ed4_IMTCPXvRcRfuLG_TLEY,37254 +werkzeug/routing/matcher.py,sha256=FyPG45iqR1XwxFujejSqfNEKV7IgbR2td7Jp-ocSASY,7817 +werkzeug/routing/rules.py,sha256=O9FHwCWclj_MskT0fn49UC2JI_OYWIx4BrPbO9JFssw,32012 +werkzeug/sansio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +werkzeug/sansio/__pycache__/__init__.cpython-311.pyc,, +werkzeug/sansio/__pycache__/http.cpython-311.pyc,, +werkzeug/sansio/__pycache__/multipart.cpython-311.pyc,, +werkzeug/sansio/__pycache__/request.cpython-311.pyc,, +werkzeug/sansio/__pycache__/response.cpython-311.pyc,, +werkzeug/sansio/__pycache__/utils.cpython-311.pyc,, +werkzeug/sansio/http.py,sha256=mKTbXo_squCAZKjt9yzfPFV8ZqQbfa6mjdc6XoeLNZ0,6234 +werkzeug/sansio/multipart.py,sha256=VTP_jhRRxYDX-1_1oge_b2CK3KTLnw3LB0k8b2zpiHI,11087 +werkzeug/sansio/request.py,sha256=wEeVGySwlOfJT5xlgQzjJOe2ksky70CJT75QTzkvfqM,24243 +werkzeug/sansio/response.py,sha256=WSsWrz-6FjtrRKun3Ha0a4sF78Su0kp8IzfrgmU_WOI,29011 +werkzeug/sansio/utils.py,sha256=DCMLtg4S5TuNtaJl6PTHMNAUDdIegmEcMFwciq-x0ag,4908 +werkzeug/security.py,sha256=gEH8qD5Ykgn6W6PgMx2CQx-iNqJFenXXqOGiWDi_3eE,5814 +werkzeug/serving.py,sha256=HUyO2O5FYcvajDc8A6gGOt7gC01wk9sljugxxHYG7lU,39223 +werkzeug/test.py,sha256=OVpg33rnFwDJ5Jya7639PKztEB7N32WAoQTVqH1p6zo,55645 +werkzeug/testapp.py,sha256=w9AdbZcmSvydD-OP6EjxVENuaZof9MkbYNFVALhcoqQ,6151 +werkzeug/urls.py,sha256=ZaFNqg6N4HUpC2yqPuQMKk7-psV-XcF4oITFuSjrOwM,45683 +werkzeug/user_agent.py,sha256=lSlLYKCcbzCUSkbdAoO8zPk2UR-8Mdn6iu_iA2kYPBA,1416 +werkzeug/utils.py,sha256=DYkOtfDR_Wc3ro3_peReo9KkUC-6yhOvz27_PUAckbA,24654 +werkzeug/wrappers/__init__.py,sha256=kGyK7rOud3qCxll_jFyW15YarJhj1xtdf3ocx9ZheB8,120 +werkzeug/wrappers/__pycache__/__init__.cpython-311.pyc,, +werkzeug/wrappers/__pycache__/request.cpython-311.pyc,, +werkzeug/wrappers/__pycache__/response.cpython-311.pyc,, +werkzeug/wrappers/request.py,sha256=PBVRWxH-BM0EykdlKYdhvqhCPP6uYLpNWKnjiTTNrFA,24984 +werkzeug/wrappers/response.py,sha256=FfGesquK6cSdPTFZvzV42CM__Ohta2cxNqLBDRkAuKA,32664 +werkzeug/wsgi.py,sha256=PGkhajtHnJj2NqYpYW_T8w17JJbaH8iI0wHHNkPvJKs,29153 diff --git a/.venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/WHEEL b/.venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/WHEEL new file mode 100644 index 000000000..1f37c02f2 --- /dev/null +++ b/.venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.40.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/.venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/top_level.txt b/.venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/top_level.txt new file mode 100644 index 000000000..6fe8da849 --- /dev/null +++ b/.venv/Lib/site-packages/Werkzeug-2.3.4.dist-info/top_level.txt @@ -0,0 +1 @@ +werkzeug diff --git a/.venv/Lib/site-packages/__pycache__/typing_extensions.cpython-311.pyc b/.venv/Lib/site-packages/__pycache__/typing_extensions.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..06ab2ba2b714cecfd658dcd6220dd03e784be0b9 GIT binary patch literal 101808 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 QHIQm8d!{#->M;QSU*0caLjV8( literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/_distutils_hack/__init__.py b/.venv/Lib/site-packages/_distutils_hack/__init__.py new file mode 100644 index 000000000..f987a5367 --- /dev/null +++ b/.venv/Lib/site-packages/_distutils_hack/__init__.py @@ -0,0 +1,222 @@ +# don't import any costly modules +import sys +import os + + +is_pypy = '__pypy__' in sys.builtin_module_names + + +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 + import warnings + + 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 + import warnings + + warnings.warn("Setuptools is replacing distutils.") + mods = [ + name + for name in sys.modules + if name == "distutils" or name.startswith("distutils.") + ] + for name in mods: + del sys.modules[name] + + +def enabled(): + """ + Allow selection of distutils by environment variable. + """ + which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'local') + return which == 'local' + + +def ensure_local_distutils(): + import importlib + + clear_distutils() + + # With the DistutilsMetaFinder in place, + # perform an import to cause distutils to be + # loaded from setuptools._distutils. Ref #2906. + with shim(): + importlib.import_module('distutils') + + # check that submodules load as expected + core = importlib.import_module('distutils.core') + assert '_distutils' in core.__file__, core.__file__ + assert 'setuptools._distutils.log' not in sys.modules + + +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 _TrivialRe: + def __init__(self, *patterns): + self._patterns = patterns + + def match(self, string): + return all(pat in string for pat in self._patterns) + + +class DistutilsMetaFinder: + def find_spec(self, fullname, path, target=None): + # optimization: only consider top level modules and those + # found in the CPython test suite. + if path is not None and not fullname.startswith('test.'): + return + + method_name = 'spec_for_{fullname}'.format(**locals()) + method = getattr(self, method_name, lambda: None) + return method() + + def spec_for_distutils(self): + if self.is_cpython(): + return + + import importlib + import importlib.abc + import importlib.util + + try: + mod = importlib.import_module('setuptools._distutils') + except Exception: + # There are a couple of cases where setuptools._distutils + # may not be present: + # - An older Setuptools without a local distutils is + # taking precedence. Ref #2957. + # - Path manipulation during sitecustomize removes + # setuptools from the path but only after the hook + # has been loaded. Ref #2980. + # In either case, fall back to stdlib behavior. + return + + class DistutilsLoader(importlib.abc.Loader): + def create_module(self, spec): + mod.__name__ = 'distutils' + return mod + + def exec_module(self, module): + pass + + return importlib.util.spec_from_loader( + 'distutils', DistutilsLoader(), origin=mod.__file__ + ) + + @staticmethod + def is_cpython(): + """ + Suppress supplying distutils for CPython (build and tests). + Ref #2965 and #3007. + """ + return os.path.isfile('pybuilddir.txt') + + 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 + + @classmethod + def pip_imported_during_build(cls): + """ + Detect if pip is being imported in a build script. Ref #2355. + """ + import traceback + + return any( + cls.frame_file_is_setup(frame) for frame, line in traceback.walk_stack(None) + ) + + @staticmethod + def frame_file_is_setup(frame): + """ + Return True if the indicated frame suggests a setup.py file. + """ + # some frames may not have __file__ (#2940) + return frame.f_globals.get('__file__', '').endswith('setup.py') + + def spec_for_sensitive_tests(self): + """ + Ensure stdlib distutils when running select tests under CPython. + + python/cpython#91169 + """ + clear_distutils() + self.spec_for_distutils = lambda: None + + sensitive_tests = ( + [ + 'test.test_distutils', + 'test.test_peg_generator', + 'test.test_importlib', + ] + if sys.version_info < (3, 10) + else [ + 'test.test_distutils', + ] + ) + + +for name in DistutilsMetaFinder.sensitive_tests: + setattr( + DistutilsMetaFinder, + f'spec_for_{name}', + DistutilsMetaFinder.spec_for_sensitive_tests, + ) + + +DISTUTILS_FINDER = DistutilsMetaFinder() + + +def add_shim(): + DISTUTILS_FINDER in sys.meta_path or insert_shim() + + +class shim: + def __enter__(self): + insert_shim() + + def __exit__(self, exc, value, tb): + remove_shim() + + +def insert_shim(): + sys.meta_path.insert(0, DISTUTILS_FINDER) + + +def remove_shim(): + try: + sys.meta_path.remove(DISTUTILS_FINDER) + except ValueError: + pass diff --git a/.venv/Lib/site-packages/_distutils_hack/__pycache__/__init__.cpython-311.pyc b/.venv/Lib/site-packages/_distutils_hack/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b8f77534e085165bb48b03758ab6658cbc6caed5 GIT binary patch literal 11175 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/_distutils_hack/__pycache__/override.cpython-311.pyc b/.venv/Lib/site-packages/_distutils_hack/__pycache__/override.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6a3bd37b790c2c82fd3b5822ecc0d096a81e2aa0 GIT binary patch literal 332 zcmZ3^%ge<81iKa|r04+Y#~=<2Fhd!i9e|AK3``8E3@HrD7#SE=12F_FfU{sCAbJ@P zuZ9aSGNdpDGiWm1;*U?sEG{W6$;>H^&qz$p_5+G>#m8sn7UUO|#K+&_PRWnYFH0>d z%1lXJ$?zFuz^_zitC-N@)S}`TkHn8ZsrXtwLatkNr}{Ka9Do1apelWJGQ z0kjq5sbUQv@qw9nuQO;~V$i(EpnZiw`vMFVu>lnW0P-|g AP5=M^ literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/_distutils_hack/override.py b/.venv/Lib/site-packages/_distutils_hack/override.py new file mode 100644 index 000000000..2cc433a4a --- /dev/null +++ b/.venv/Lib/site-packages/_distutils_hack/override.py @@ -0,0 +1 @@ +__import__('_distutils_hack').do_override() diff --git a/.venv/Lib/site-packages/blinker-1.6.2.dist-info/INSTALLER b/.venv/Lib/site-packages/blinker-1.6.2.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/.venv/Lib/site-packages/blinker-1.6.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/Lib/site-packages/blinker-1.6.2.dist-info/LICENSE.rst b/.venv/Lib/site-packages/blinker-1.6.2.dist-info/LICENSE.rst new file mode 100644 index 000000000..79c9825ad --- /dev/null +++ b/.venv/Lib/site-packages/blinker-1.6.2.dist-info/LICENSE.rst @@ -0,0 +1,20 @@ +Copyright 2010 Jason Kirtland + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/.venv/Lib/site-packages/blinker-1.6.2.dist-info/METADATA b/.venv/Lib/site-packages/blinker-1.6.2.dist-info/METADATA new file mode 100644 index 000000000..d181f19f3 --- /dev/null +++ b/.venv/Lib/site-packages/blinker-1.6.2.dist-info/METADATA @@ -0,0 +1,63 @@ +Metadata-Version: 2.1 +Name: blinker +Version: 1.6.2 +Summary: Fast, simple object-to-object and broadcast signaling +Author-email: Jason Kirtland +Maintainer-email: Pallets Ecosystem +License: MIT License +Project-URL: Homepage, https://blinker.readthedocs.io +Project-URL: Documentation, https://blinker.readthedocs.io +Project-URL: Source Code, https://github.com/pallets-eco/blinker/ +Project-URL: Issue Tracker, https://github.com/pallets-eco/blinker/issues/ +Project-URL: Chat, https://discord.gg/pallets +Keywords: signal,emit,events,broadcast +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Software Development :: Libraries +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst + +Blinker +======= + +Blinker provides a fast dispatching system that allows any number of +interested parties to subscribe to events, or "signals". + +Signal receivers can subscribe to specific senders or receive signals +sent by any sender. + +.. code-block:: pycon + + >>> from blinker import signal + >>> started = signal('round-started') + >>> def each(round): + ... print(f"Round {round}") + ... + >>> started.connect(each) + + >>> def round_two(round): + ... print("This is round two.") + ... + >>> started.connect(round_two, sender=2) + + >>> for round in range(1, 4): + ... started.send(round) + ... + Round 1! + Round 2! + This is round two. + Round 3! + + +Links +----- + +- Documentation: https://blinker.readthedocs.io/ +- Changes: https://blinker.readthedocs.io/#changes +- PyPI Releases: https://pypi.org/project/blinker/ +- Source Code: https://github.com/pallets-eco/blinker/ +- Issue Tracker: https://github.com/pallets-eco/blinker/issues/ diff --git a/.venv/Lib/site-packages/blinker-1.6.2.dist-info/RECORD b/.venv/Lib/site-packages/blinker-1.6.2.dist-info/RECORD new file mode 100644 index 000000000..5eefe3d7d --- /dev/null +++ b/.venv/Lib/site-packages/blinker-1.6.2.dist-info/RECORD @@ -0,0 +1,15 @@ +blinker-1.6.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +blinker-1.6.2.dist-info/LICENSE.rst,sha256=nrc6HzhZekqhcCXSrhvjg5Ykx5XphdTw6Xac4p-spGc,1054 +blinker-1.6.2.dist-info/METADATA,sha256=7MRskabu2wQvWIMFwgqP3w2LDt8nR5nCxH7Anu1ZrBM,1964 +blinker-1.6.2.dist-info/RECORD,, +blinker-1.6.2.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92 +blinker-1.6.2.dist-info/top_level.txt,sha256=2NmsENM0J2t9Z8mkjxHDmGMQj7Bm8f5ZTTYe1x1fZtM,8 +blinker/__init__.py,sha256=Ko7EbvxyCl_UewgsP8XgDJqJcHZA7EsuhG72R_zDrcY,408 +blinker/__pycache__/__init__.cpython-311.pyc,, +blinker/__pycache__/_saferef.cpython-311.pyc,, +blinker/__pycache__/_utilities.cpython-311.pyc,, +blinker/__pycache__/base.cpython-311.pyc,, +blinker/_saferef.py,sha256=kWOTIWnCY3kOb8lZP74Rbx7bR_BLVg4TjwzNCRLhKHs,9096 +blinker/_utilities.py,sha256=GPXtJzykzVotoxHC79mgFQMPJtICwpVDCCpus4_JtsA,4110 +blinker/base.py,sha256=7Y-C0ZVIe-NrrskPeqj0bLSp4R6Cpq5LrzI1DmLqMEA,20469 +blinker/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/.venv/Lib/site-packages/blinker-1.6.2.dist-info/WHEEL b/.venv/Lib/site-packages/blinker-1.6.2.dist-info/WHEEL new file mode 100644 index 000000000..1f37c02f2 --- /dev/null +++ b/.venv/Lib/site-packages/blinker-1.6.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.40.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/.venv/Lib/site-packages/blinker-1.6.2.dist-info/top_level.txt b/.venv/Lib/site-packages/blinker-1.6.2.dist-info/top_level.txt new file mode 100644 index 000000000..1ff4ca551 --- /dev/null +++ b/.venv/Lib/site-packages/blinker-1.6.2.dist-info/top_level.txt @@ -0,0 +1 @@ +blinker diff --git a/.venv/Lib/site-packages/blinker/__init__.py b/.venv/Lib/site-packages/blinker/__init__.py new file mode 100644 index 000000000..71d66d3bd --- /dev/null +++ b/.venv/Lib/site-packages/blinker/__init__.py @@ -0,0 +1,19 @@ +from blinker.base import ANY +from blinker.base import NamedSignal +from blinker.base import Namespace +from blinker.base import receiver_connected +from blinker.base import Signal +from blinker.base import signal +from blinker.base import WeakNamespace + +__all__ = [ + "ANY", + "NamedSignal", + "Namespace", + "Signal", + "WeakNamespace", + "receiver_connected", + "signal", +] + +__version__ = "1.6.2" diff --git a/.venv/Lib/site-packages/blinker/__pycache__/__init__.cpython-311.pyc b/.venv/Lib/site-packages/blinker/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..956eb08db4deb1b61010c0ae1a7eb360f0be45d4 GIT binary patch literal 653 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/blinker/__pycache__/_utilities.cpython-311.pyc b/.venv/Lib/site-packages/blinker/__pycache__/_utilities.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e9de6cad2a77b94189150216235d6c48832500d5 GIT binary patch literal 6713 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/blinker/_saferef.py b/.venv/Lib/site-packages/blinker/_saferef.py new file mode 100644 index 000000000..dcb70c189 --- /dev/null +++ b/.venv/Lib/site-packages/blinker/_saferef.py @@ -0,0 +1,230 @@ +# extracted from Louie, http://pylouie.org/ +# updated for Python 3 +# +# Copyright (c) 2006 Patrick K. O'Brien, Mike C. Fletcher, +# Matthew R. Scott +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# * Neither the name of the 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 +# OWNER 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. +# +"""Refactored 'safe reference from dispatcher.py""" +import operator +import sys +import traceback +import weakref + + +get_self = operator.attrgetter("__self__") +get_func = operator.attrgetter("__func__") + + +def safe_ref(target, on_delete=None): + """Return a *safe* weak reference to a callable target. + + - ``target``: The object to be weakly referenced, if it's a bound + method reference, will create a BoundMethodWeakref, otherwise + creates a simple weakref. + + - ``on_delete``: If provided, will have a hard reference stored to + the callable to be called after the safe reference goes out of + scope with the reference object, (either a weakref or a + BoundMethodWeakref) as argument. + """ + try: + im_self = get_self(target) + except AttributeError: + if callable(on_delete): + return weakref.ref(target, on_delete) + else: + return weakref.ref(target) + else: + if im_self is not None: + # Turn a bound method into a BoundMethodWeakref instance. + # Keep track of these instances for lookup by disconnect(). + assert hasattr(target, "im_func") or hasattr(target, "__func__"), ( + f"safe_ref target {target!r} has im_self, but no im_func, " + "don't know how to create reference" + ) + reference = BoundMethodWeakref(target=target, on_delete=on_delete) + return reference + + +class BoundMethodWeakref: + """'Safe' and reusable weak references to instance methods. + + BoundMethodWeakref objects provide a mechanism for referencing a + bound method without requiring that the method object itself + (which is normally a transient object) is kept alive. Instead, + the BoundMethodWeakref object keeps weak references to both the + object and the function which together define the instance method. + + Attributes: + + - ``key``: The identity key for the reference, calculated by the + class's calculate_key method applied to the target instance method. + + - ``deletion_methods``: Sequence of callable objects taking single + argument, a reference to this object which will be called when + *either* the target object or target function is garbage + collected (i.e. when this object becomes invalid). These are + specified as the on_delete parameters of safe_ref calls. + + - ``weak_self``: Weak reference to the target object. + + - ``weak_func``: Weak reference to the target function. + + Class Attributes: + + - ``_all_instances``: Class attribute pointing to all live + BoundMethodWeakref objects indexed by the class's + calculate_key(target) method applied to the target objects. + This weak value dictionary is used to short-circuit creation so + that multiple references to the same (object, function) pair + produce the same BoundMethodWeakref instance. + """ + + _all_instances = weakref.WeakValueDictionary() # type: ignore[var-annotated] + + def __new__(cls, target, on_delete=None, *arguments, **named): + """Create new instance or return current instance. + + Basically this method of construction allows us to + short-circuit creation of references to already-referenced + instance methods. The key corresponding to the target is + calculated, and if there is already an existing reference, + that is returned, with its deletion_methods attribute updated. + Otherwise the new instance is created and registered in the + table of already-referenced methods. + """ + key = cls.calculate_key(target) + current = cls._all_instances.get(key) + if current is not None: + current.deletion_methods.append(on_delete) + return current + else: + base = super().__new__(cls) + cls._all_instances[key] = base + base.__init__(target, on_delete, *arguments, **named) + return base + + def __init__(self, target, on_delete=None): + """Return a weak-reference-like instance for a bound method. + + - ``target``: The instance-method target for the weak reference, + must have im_self and im_func attributes and be + reconstructable via the following, which is true of built-in + instance methods:: + + target.im_func.__get__( target.im_self ) + + - ``on_delete``: Optional callback which will be called when + this weak reference ceases to be valid (i.e. either the + object or the function is garbage collected). Should take a + single argument, which will be passed a pointer to this + object. + """ + + def remove(weak, self=self): + """Set self.isDead to True when method or instance is destroyed.""" + methods = self.deletion_methods[:] + del self.deletion_methods[:] + try: + del self.__class__._all_instances[self.key] + except KeyError: + pass + for function in methods: + try: + if callable(function): + function(self) + except Exception: + try: + traceback.print_exc() + except AttributeError: + e = sys.exc_info()[1] + print( + f"Exception during saferef {self} " + f"cleanup function {function}: {e}" + ) + + self.deletion_methods = [on_delete] + self.key = self.calculate_key(target) + im_self = get_self(target) + im_func = get_func(target) + self.weak_self = weakref.ref(im_self, remove) + self.weak_func = weakref.ref(im_func, remove) + self.self_name = str(im_self) + self.func_name = str(im_func.__name__) + + @classmethod + def calculate_key(cls, target): + """Calculate the reference key for this reference. + + Currently this is a two-tuple of the id()'s of the target + object and the target function respectively. + """ + return (id(get_self(target)), id(get_func(target))) + + def __str__(self): + """Give a friendly representation of the object.""" + return "{}({}.{})".format( + self.__class__.__name__, + self.self_name, + self.func_name, + ) + + __repr__ = __str__ + + def __hash__(self): + return hash((self.self_name, self.key)) + + def __nonzero__(self): + """Whether we are still a valid reference.""" + return self() is not None + + def __eq__(self, other): + """Compare with another reference.""" + if not isinstance(other, self.__class__): + return operator.eq(self.__class__, type(other)) + return operator.eq(self.key, other.key) + + def __call__(self): + """Return a strong reference to the bound method. + + If the target cannot be retrieved, then will return None, + otherwise returns a bound instance method for our object and + function. + + Note: You may call this method any number of times, as it does + not invalidate the reference. + """ + target = self.weak_self() + if target is not None: + function = self.weak_func() + if function is not None: + return function.__get__(target) + return None diff --git a/.venv/Lib/site-packages/blinker/_utilities.py b/.venv/Lib/site-packages/blinker/_utilities.py new file mode 100644 index 000000000..068d94cec --- /dev/null +++ b/.venv/Lib/site-packages/blinker/_utilities.py @@ -0,0 +1,142 @@ +from __future__ import annotations + +import asyncio +import inspect +import sys +import typing as t +from functools import partial +from weakref import ref + +from blinker._saferef import BoundMethodWeakref + +IdentityType = t.Union[t.Tuple[int, int], str, int] + + +class _symbol: + def __init__(self, name): + """Construct a new named symbol.""" + self.__name__ = self.name = name + + def __reduce__(self): + return symbol, (self.name,) + + def __repr__(self): + return self.name + + +_symbol.__name__ = "symbol" + + +class symbol: + """A constant symbol. + + >>> symbol('foo') is symbol('foo') + True + >>> symbol('foo') + foo + + A slight refinement of the MAGICCOOKIE=object() pattern. The primary + advantage of symbol() is its repr(). They are also singletons. + + Repeated calls of symbol('name') will all return the same instance. + + """ + + symbols = {} # type: ignore[var-annotated] + + def __new__(cls, name): + try: + return cls.symbols[name] + except KeyError: + return cls.symbols.setdefault(name, _symbol(name)) + + +def hashable_identity(obj: object) -> IdentityType: + if hasattr(obj, "__func__"): + return (id(obj.__func__), id(obj.__self__)) # type: ignore[attr-defined] + elif hasattr(obj, "im_func"): + return (id(obj.im_func), id(obj.im_self)) # type: ignore[attr-defined] + elif isinstance(obj, (int, str)): + return obj + else: + return id(obj) + + +WeakTypes = (ref, BoundMethodWeakref) + + +class annotatable_weakref(ref): + """A weakref.ref that supports custom instance attributes.""" + + receiver_id: t.Optional[IdentityType] + sender_id: t.Optional[IdentityType] + + +def reference( # type: ignore[no-untyped-def] + object, callback=None, **annotations +) -> annotatable_weakref: + """Return an annotated weak ref.""" + if callable(object): + weak = callable_reference(object, callback) + else: + weak = annotatable_weakref(object, callback) + for key, value in annotations.items(): + setattr(weak, key, value) + return weak # type: ignore[no-any-return] + + +def callable_reference(object, callback=None): + """Return an annotated weak ref, supporting bound instance methods.""" + if hasattr(object, "im_self") and object.im_self is not None: + return BoundMethodWeakref(target=object, on_delete=callback) + elif hasattr(object, "__self__") and object.__self__ is not None: + return BoundMethodWeakref(target=object, on_delete=callback) + return annotatable_weakref(object, callback) + + +class lazy_property: + """A @property that is only evaluated once.""" + + def __init__(self, deferred): + self._deferred = deferred + self.__doc__ = deferred.__doc__ + + def __get__(self, obj, cls): + if obj is None: + return self + value = self._deferred(obj) + setattr(obj, self._deferred.__name__, value) + return value + + +def is_coroutine_function(func: t.Any) -> bool: + # Python < 3.8 does not correctly determine partially wrapped + # coroutine functions are coroutine functions, hence the need for + # this to exist. Code taken from CPython. + if sys.version_info >= (3, 8): + return asyncio.iscoroutinefunction(func) + else: + # Note that there is something special about the AsyncMock + # such that it isn't determined as a coroutine function + # without an explicit check. + try: + from unittest.mock import AsyncMock # type: ignore[attr-defined] + + if isinstance(func, AsyncMock): + return True + except ImportError: + # Not testing, no asynctest to import + pass + + while inspect.ismethod(func): + func = func.__func__ + while isinstance(func, partial): + func = func.func + if not inspect.isfunction(func): + return False + + if func.__code__.co_flags & inspect.CO_COROUTINE: + return True + + acic = asyncio.coroutines._is_coroutine # type: ignore[attr-defined] + return getattr(func, "_is_coroutine", None) is acic diff --git a/.venv/Lib/site-packages/blinker/base.py b/.venv/Lib/site-packages/blinker/base.py new file mode 100644 index 000000000..80e24e21c --- /dev/null +++ b/.venv/Lib/site-packages/blinker/base.py @@ -0,0 +1,551 @@ +"""Signals and events. + +A small implementation of signals, inspired by a snippet of Django signal +API client code seen in a blog post. Signals are first-class objects and +each manages its own receivers and message emission. + +The :func:`signal` function provides singleton behavior for named signals. + +""" +from __future__ import annotations + +import typing as t +from collections import defaultdict +from contextlib import contextmanager +from warnings import warn +from weakref import WeakValueDictionary + +from blinker._utilities import annotatable_weakref +from blinker._utilities import hashable_identity +from blinker._utilities import IdentityType +from blinker._utilities import is_coroutine_function +from blinker._utilities import lazy_property +from blinker._utilities import reference +from blinker._utilities import symbol +from blinker._utilities import WeakTypes + +if t.TYPE_CHECKING: + import typing_extensions as te + + T_callable = t.TypeVar("T_callable", bound=t.Callable[..., t.Any]) + + T = t.TypeVar("T") + P = te.ParamSpec("P") + + AsyncWrapperType = t.Callable[[t.Callable[P, T]], t.Callable[P, t.Awaitable[T]]] + SyncWrapperType = t.Callable[[t.Callable[P, t.Awaitable[T]]], t.Callable[P, T]] + +ANY = symbol("ANY") +ANY.__doc__ = 'Token for "any sender".' +ANY_ID = 0 + + +class Signal: + """A notification emitter.""" + + #: An :obj:`ANY` convenience synonym, allows ``Signal.ANY`` + #: without an additional import. + ANY = ANY + + @lazy_property + def receiver_connected(self) -> Signal: + """Emitted after each :meth:`connect`. + + The signal sender is the signal instance, and the :meth:`connect` + arguments are passed through: *receiver*, *sender*, and *weak*. + + .. versionadded:: 1.2 + + """ + return Signal(doc="Emitted after a receiver connects.") + + @lazy_property + def receiver_disconnected(self) -> Signal: + """Emitted after :meth:`disconnect`. + + The sender is the signal instance, and the :meth:`disconnect` arguments + are passed through: *receiver* and *sender*. + + Note, this signal is emitted **only** when :meth:`disconnect` is + called explicitly. + + The disconnect signal can not be emitted by an automatic disconnect + (due to a weakly referenced receiver or sender going out of scope), + as the receiver and/or sender instances are no longer available for + use at the time this signal would be emitted. + + An alternative approach is available by subscribing to + :attr:`receiver_connected` and setting up a custom weakref cleanup + callback on weak receivers and senders. + + .. versionadded:: 1.2 + + """ + return Signal(doc="Emitted after a receiver disconnects.") + + def __init__(self, doc: str | None = None) -> None: + """ + :param doc: optional. If provided, will be assigned to the signal's + __doc__ attribute. + + """ + if doc: + self.__doc__ = doc + #: A mapping of connected receivers. + #: + #: The values of this mapping are not meaningful outside of the + #: internal :class:`Signal` implementation, however the boolean value + #: of the mapping is useful as an extremely efficient check to see if + #: any receivers are connected to the signal. + self.receivers: dict[IdentityType, t.Callable | annotatable_weakref] = {} + self.is_muted = False + self._by_receiver: dict[IdentityType, set[IdentityType]] = defaultdict(set) + self._by_sender: dict[IdentityType, set[IdentityType]] = defaultdict(set) + self._weak_senders: dict[IdentityType, annotatable_weakref] = {} + + def connect( + self, receiver: T_callable, sender: t.Any = ANY, weak: bool = True + ) -> T_callable: + """Connect *receiver* to signal events sent by *sender*. + + :param receiver: A callable. Will be invoked by :meth:`send` with + `sender=` as a single positional argument and any ``kwargs`` that + were provided to a call to :meth:`send`. + + :param sender: Any object or :obj:`ANY`, defaults to ``ANY``. + Restricts notifications delivered to *receiver* to only those + :meth:`send` emissions sent by *sender*. If ``ANY``, the receiver + will always be notified. A *receiver* may be connected to + multiple *sender* values on the same Signal through multiple calls + to :meth:`connect`. + + :param weak: If true, the Signal will hold a weakref to *receiver* + and automatically disconnect when *receiver* goes out of scope or + is garbage collected. Defaults to True. + + """ + receiver_id = hashable_identity(receiver) + receiver_ref: T_callable | annotatable_weakref + + if weak: + receiver_ref = reference(receiver, self._cleanup_receiver) + receiver_ref.receiver_id = receiver_id + else: + receiver_ref = receiver + sender_id: IdentityType + if sender is ANY: + sender_id = ANY_ID + else: + sender_id = hashable_identity(sender) + + self.receivers.setdefault(receiver_id, receiver_ref) + self._by_sender[sender_id].add(receiver_id) + self._by_receiver[receiver_id].add(sender_id) + del receiver_ref + + if sender is not ANY and sender_id not in self._weak_senders: + # wire together a cleanup for weakref-able senders + try: + sender_ref = reference(sender, self._cleanup_sender) + sender_ref.sender_id = sender_id + except TypeError: + pass + else: + self._weak_senders.setdefault(sender_id, sender_ref) + del sender_ref + + # broadcast this connection. if receivers raise, disconnect. + if "receiver_connected" in self.__dict__ and self.receiver_connected.receivers: + try: + self.receiver_connected.send( + self, receiver=receiver, sender=sender, weak=weak + ) + except TypeError as e: + self.disconnect(receiver, sender) + raise e + if receiver_connected.receivers and self is not receiver_connected: + try: + receiver_connected.send( + self, receiver_arg=receiver, sender_arg=sender, weak_arg=weak + ) + except TypeError as e: + self.disconnect(receiver, sender) + raise e + return receiver + + def connect_via( + self, sender: t.Any, weak: bool = False + ) -> t.Callable[[T_callable], T_callable]: + """Connect the decorated function as a receiver for *sender*. + + :param sender: Any object or :obj:`ANY`. The decorated function + will only receive :meth:`send` emissions sent by *sender*. If + ``ANY``, the receiver will always be notified. A function may be + decorated multiple times with differing *sender* values. + + :param weak: If true, the Signal will hold a weakref to the + decorated function and automatically disconnect when *receiver* + goes out of scope or is garbage collected. Unlike + :meth:`connect`, this defaults to False. + + The decorated function will be invoked by :meth:`send` with + `sender=` as a single positional argument and any ``kwargs`` that + were provided to the call to :meth:`send`. + + + .. versionadded:: 1.1 + + """ + + def decorator(fn: T_callable) -> T_callable: + self.connect(fn, sender, weak) + return fn + + return decorator + + @contextmanager + def connected_to( + self, receiver: t.Callable, sender: t.Any = ANY + ) -> t.Generator[None, None, None]: + """Execute a block with the signal temporarily connected to *receiver*. + + :param receiver: a receiver callable + :param sender: optional, a sender to filter on + + This is a context manager for use in the ``with`` statement. It can + be useful in unit tests. *receiver* is connected to the signal for + the duration of the ``with`` block, and will be disconnected + automatically when exiting the block: + + .. code-block:: python + + with on_ready.connected_to(receiver): + # do stuff + on_ready.send(123) + + .. versionadded:: 1.1 + + """ + self.connect(receiver, sender=sender, weak=False) + try: + yield None + except Exception as e: + self.disconnect(receiver) + raise e + else: + self.disconnect(receiver) + + @contextmanager + def muted(self) -> t.Generator[None, None, None]: + """Context manager for temporarily disabling signal. + Useful for test purposes. + """ + self.is_muted = True + try: + yield None + except Exception as e: + raise e + finally: + self.is_muted = False + + def temporarily_connected_to( + self, receiver: t.Callable, sender: t.Any = ANY + ) -> t.ContextManager[None]: + """An alias for :meth:`connected_to`. + + :param receiver: a receiver callable + :param sender: optional, a sender to filter on + + .. versionadded:: 0.9 + + .. versionchanged:: 1.1 + Renamed to :meth:`connected_to`. ``temporarily_connected_to`` was + deprecated in 1.2 and will be removed in a subsequent version. + + """ + warn( + "temporarily_connected_to is deprecated; use connected_to instead.", + DeprecationWarning, + ) + return self.connected_to(receiver, sender) + + def send( + self, + *sender: t.Any, + _async_wrapper: AsyncWrapperType | None = None, + **kwargs: t.Any, + ) -> list[tuple[t.Callable, t.Any]]: + """Emit this signal on behalf of *sender*, passing on ``kwargs``. + + Returns a list of 2-tuples, pairing receivers with their return + value. The ordering of receiver notification is undefined. + + :param sender: Any object or ``None``. If omitted, synonymous + with ``None``. Only accepts one positional argument. + :param _async_wrapper: A callable that should wrap a coroutine + receiver and run it when called synchronously. + + :param kwargs: Data to be sent to receivers. + """ + if self.is_muted: + return [] + + sender = self._extract_sender(sender) + results = [] + for receiver in self.receivers_for(sender): + if is_coroutine_function(receiver): + if _async_wrapper is None: + raise RuntimeError("Cannot send to a coroutine function") + receiver = _async_wrapper(receiver) + result = receiver(sender, **kwargs) # type: ignore[call-arg] + results.append((receiver, result)) + return results + + async def send_async( + self, + *sender: t.Any, + _sync_wrapper: SyncWrapperType | None = None, + **kwargs: t.Any, + ) -> list[tuple[t.Callable, t.Any]]: + """Emit this signal on behalf of *sender*, passing on ``kwargs``. + + Returns a list of 2-tuples, pairing receivers with their return + value. The ordering of receiver notification is undefined. + + :param sender: Any object or ``None``. If omitted, synonymous + with ``None``. Only accepts one positional argument. + :param _sync_wrapper: A callable that should wrap a synchronous + receiver and run it when awaited. + + :param kwargs: Data to be sent to receivers. + """ + if self.is_muted: + return [] + + sender = self._extract_sender(sender) + results = [] + for receiver in self.receivers_for(sender): + if not is_coroutine_function(receiver): + if _sync_wrapper is None: + raise RuntimeError("Cannot send to a non-coroutine function") + receiver = _sync_wrapper(receiver) # type: ignore[arg-type] + result = await receiver(sender, **kwargs) # type: ignore[call-arg, misc] + results.append((receiver, result)) + return results + + def _extract_sender(self, sender: t.Any) -> t.Any: + if not self.receivers: + # Ensure correct signature even on no-op sends, disable with -O + # for lowest possible cost. + if __debug__ and sender and len(sender) > 1: + raise TypeError( + f"send() accepts only one positional argument, {len(sender)} given" + ) + return [] + + # Using '*sender' rather than 'sender=None' allows 'sender' to be + # used as a keyword argument- i.e. it's an invisible name in the + # function signature. + if len(sender) == 0: + sender = None + elif len(sender) > 1: + raise TypeError( + f"send() accepts only one positional argument, {len(sender)} given" + ) + else: + sender = sender[0] + return sender + + def has_receivers_for(self, sender: t.Any) -> bool: + """True if there is probably a receiver for *sender*. + + Performs an optimistic check only. Does not guarantee that all + weakly referenced receivers are still alive. See + :meth:`receivers_for` for a stronger search. + + """ + if not self.receivers: + return False + if self._by_sender[ANY_ID]: + return True + if sender is ANY: + return False + return hashable_identity(sender) in self._by_sender + + def receivers_for( + self, sender: t.Any + ) -> t.Generator[t.Callable | annotatable_weakref, None, None]: + """Iterate all live receivers listening for *sender*.""" + # TODO: test receivers_for(ANY) + if self.receivers: + sender_id = hashable_identity(sender) + if sender_id in self._by_sender: + ids = self._by_sender[ANY_ID] | self._by_sender[sender_id] + else: + ids = self._by_sender[ANY_ID].copy() + for receiver_id in ids: + receiver = self.receivers.get(receiver_id) + if receiver is None: + continue + if isinstance(receiver, WeakTypes): + strong = receiver() + if strong is None: + self._disconnect(receiver_id, ANY_ID) + continue + receiver = strong + yield receiver # type: ignore[misc] + + def disconnect(self, receiver: t.Callable, sender: t.Any = ANY) -> None: + """Disconnect *receiver* from this signal's events. + + :param receiver: a previously :meth:`connected` callable + + :param sender: a specific sender to disconnect from, or :obj:`ANY` + to disconnect from all senders. Defaults to ``ANY``. + + """ + sender_id: IdentityType + if sender is ANY: + sender_id = ANY_ID + else: + sender_id = hashable_identity(sender) + receiver_id = hashable_identity(receiver) + self._disconnect(receiver_id, sender_id) + + if ( + "receiver_disconnected" in self.__dict__ + and self.receiver_disconnected.receivers + ): + self.receiver_disconnected.send(self, receiver=receiver, sender=sender) + + def _disconnect(self, receiver_id: IdentityType, sender_id: IdentityType) -> None: + if sender_id == ANY_ID: + if self._by_receiver.pop(receiver_id, False): + for bucket in self._by_sender.values(): + bucket.discard(receiver_id) + self.receivers.pop(receiver_id, None) + else: + self._by_sender[sender_id].discard(receiver_id) + self._by_receiver[receiver_id].discard(sender_id) + + def _cleanup_receiver(self, receiver_ref: annotatable_weakref) -> None: + """Disconnect a receiver from all senders.""" + self._disconnect(t.cast(IdentityType, receiver_ref.receiver_id), ANY_ID) + + def _cleanup_sender(self, sender_ref: annotatable_weakref) -> None: + """Disconnect all receivers from a sender.""" + sender_id = t.cast(IdentityType, sender_ref.sender_id) + assert sender_id != ANY_ID + self._weak_senders.pop(sender_id, None) + for receiver_id in self._by_sender.pop(sender_id, ()): + self._by_receiver[receiver_id].discard(sender_id) + + def _cleanup_bookkeeping(self) -> None: + """Prune unused sender/receiver bookkeeping. Not threadsafe. + + Connecting & disconnecting leave behind a small amount of bookkeeping + for the receiver and sender values. Typical workloads using Blinker, + for example in most web apps, Flask, CLI scripts, etc., are not + adversely affected by this bookkeeping. + + With a long-running Python process performing dynamic signal routing + with high volume- e.g. connecting to function closures, "senders" are + all unique object instances, and doing all of this over and over- you + may see memory usage will grow due to extraneous bookkeeping. (An empty + set() for each stale sender/receiver pair.) + + This method will prune that bookkeeping away, with the caveat that such + pruning is not threadsafe. The risk is that cleanup of a fully + disconnected receiver/sender pair occurs while another thread is + connecting that same pair. If you are in the highly dynamic, unique + receiver/sender situation that has lead you to this method, that + failure mode is perhaps not a big deal for you. + """ + for mapping in (self._by_sender, self._by_receiver): + for _id, bucket in list(mapping.items()): + if not bucket: + mapping.pop(_id, None) + + def _clear_state(self) -> None: + """Throw away all signal state. Useful for unit tests.""" + self._weak_senders.clear() + self.receivers.clear() + self._by_sender.clear() + self._by_receiver.clear() + + +receiver_connected = Signal( + """\ +Sent by a :class:`Signal` after a receiver connects. + +:argument: the Signal that was connected to +:keyword receiver_arg: the connected receiver +:keyword sender_arg: the sender to connect to +:keyword weak_arg: true if the connection to receiver_arg is a weak reference + +.. deprecated:: 1.2 + +As of 1.2, individual signals have their own private +:attr:`~Signal.receiver_connected` and +:attr:`~Signal.receiver_disconnected` signals with a slightly simplified +call signature. This global signal is planned to be removed in 1.6. + +""" +) + + +class NamedSignal(Signal): + """A named generic notification emitter.""" + + def __init__(self, name: str, doc: str | None = None) -> None: + Signal.__init__(self, doc) + + #: The name of this signal. + self.name = name + + def __repr__(self) -> str: + base = Signal.__repr__(self) + return f"{base[:-1]}; {self.name!r}>" + + +class Namespace(dict): + """A mapping of signal names to signals.""" + + def signal(self, name: str, doc: str | None = None) -> NamedSignal: + """Return the :class:`NamedSignal` *name*, creating it if required. + + Repeated calls to this function will return the same signal object. + + """ + try: + return self[name] # type: ignore[no-any-return] + except KeyError: + result = self.setdefault(name, NamedSignal(name, doc)) + return result # type: ignore[no-any-return] + + +class WeakNamespace(WeakValueDictionary): + """A weak mapping of signal names to signals. + + Automatically cleans up unused Signals when the last reference goes out + of scope. This namespace implementation exists for a measure of legacy + compatibility with Blinker <= 1.2, and may be dropped in the future. + + .. versionadded:: 1.3 + + """ + + def signal(self, name: str, doc: str | None = None) -> NamedSignal: + """Return the :class:`NamedSignal` *name*, creating it if required. + + Repeated calls to this function will return the same signal object. + + """ + try: + return self[name] # type: ignore[no-any-return] + except KeyError: + result = self.setdefault(name, NamedSignal(name, doc)) + return result # type: ignore[no-any-return] + + +signal = Namespace().signal diff --git a/.venv/Lib/site-packages/blinker/py.typed b/.venv/Lib/site-packages/blinker/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/.venv/Lib/site-packages/click-8.1.3.dist-info/INSTALLER b/.venv/Lib/site-packages/click-8.1.3.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/.venv/Lib/site-packages/click-8.1.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/Lib/site-packages/click-8.1.3.dist-info/LICENSE.rst b/.venv/Lib/site-packages/click-8.1.3.dist-info/LICENSE.rst new file mode 100644 index 000000000..d12a84918 --- /dev/null +++ b/.venv/Lib/site-packages/click-8.1.3.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2014 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/.venv/Lib/site-packages/click-8.1.3.dist-info/METADATA b/.venv/Lib/site-packages/click-8.1.3.dist-info/METADATA new file mode 100644 index 000000000..8e5dc1e0a --- /dev/null +++ b/.venv/Lib/site-packages/click-8.1.3.dist-info/METADATA @@ -0,0 +1,111 @@ +Metadata-Version: 2.1 +Name: click +Version: 8.1.3 +Summary: Composable command line interface toolkit +Home-page: https://palletsprojects.com/p/click/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://click.palletsprojects.com/ +Project-URL: Changes, https://click.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/click/ +Project-URL: Issue Tracker, https://github.com/pallets/click/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +Project-URL: Chat, https://discord.gg/pallets +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst +Requires-Dist: colorama ; platform_system == "Windows" +Requires-Dist: importlib-metadata ; python_version < "3.8" + +\$ click\_ +========== + +Click is a Python package for creating beautiful command line interfaces +in a composable way with as little code as necessary. It's the "Command +Line Interface Creation Kit". It's highly configurable but comes with +sensible defaults out of the box. + +It aims to make the process of writing command line tools quick and fun +while also preventing any frustration caused by the inability to +implement an intended CLI API. + +Click in three points: + +- Arbitrary nesting of commands +- Automatic help page generation +- Supports lazy loading of subcommands at runtime + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U click + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +A Simple Example +---------------- + +.. code-block:: python + + import click + + @click.command() + @click.option("--count", default=1, help="Number of greetings.") + @click.option("--name", prompt="Your name", help="The person to greet.") + def hello(count, name): + """Simple program that greets NAME for a total of COUNT times.""" + for _ in range(count): + click.echo(f"Hello, {name}!") + + if __name__ == '__main__': + hello() + +.. code-block:: text + + $ python hello.py --count=3 + Your name: Click + Hello, Click! + Hello, Click! + Hello, Click! + + +Donate +------ + +The Pallets organization develops and supports Click and other popular +packages. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, `please +donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://click.palletsprojects.com/ +- Changes: https://click.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/click/ +- Source Code: https://github.com/pallets/click +- Issue Tracker: https://github.com/pallets/click/issues +- Website: https://palletsprojects.com/p/click +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets + + diff --git a/.venv/Lib/site-packages/click-8.1.3.dist-info/RECORD b/.venv/Lib/site-packages/click-8.1.3.dist-info/RECORD new file mode 100644 index 000000000..3f8dc1a59 --- /dev/null +++ b/.venv/Lib/site-packages/click-8.1.3.dist-info/RECORD @@ -0,0 +1,39 @@ +click-8.1.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +click-8.1.3.dist-info/LICENSE.rst,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 +click-8.1.3.dist-info/METADATA,sha256=tFJIX5lOjx7c5LjZbdTPFVDJSgyv9F74XY0XCPp_gnc,3247 +click-8.1.3.dist-info/RECORD,, +click-8.1.3.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +click-8.1.3.dist-info/top_level.txt,sha256=J1ZQogalYS4pphY_lPECoNMfw0HzTSrZglC4Yfwo4xA,6 +click/__init__.py,sha256=rQBLutqg-z6m8nOzivIfigDn_emijB_dKv9BZ2FNi5s,3138 +click/__pycache__/__init__.cpython-311.pyc,, +click/__pycache__/_compat.cpython-311.pyc,, +click/__pycache__/_termui_impl.cpython-311.pyc,, +click/__pycache__/_textwrap.cpython-311.pyc,, +click/__pycache__/_winconsole.cpython-311.pyc,, +click/__pycache__/core.cpython-311.pyc,, +click/__pycache__/decorators.cpython-311.pyc,, +click/__pycache__/exceptions.cpython-311.pyc,, +click/__pycache__/formatting.cpython-311.pyc,, +click/__pycache__/globals.cpython-311.pyc,, +click/__pycache__/parser.cpython-311.pyc,, +click/__pycache__/shell_completion.cpython-311.pyc,, +click/__pycache__/termui.cpython-311.pyc,, +click/__pycache__/testing.cpython-311.pyc,, +click/__pycache__/types.cpython-311.pyc,, +click/__pycache__/utils.cpython-311.pyc,, +click/_compat.py,sha256=JIHLYs7Jzz4KT9t-ds4o4jBzLjnwCiJQKqur-5iwCKI,18810 +click/_termui_impl.py,sha256=qK6Cfy4mRFxvxE8dya8RBhLpSC8HjF-lvBc6aNrPdwg,23451 +click/_textwrap.py,sha256=10fQ64OcBUMuK7mFvh8363_uoOxPlRItZBmKzRJDgoY,1353 +click/_winconsole.py,sha256=5ju3jQkcZD0W27WEMGqmEP4y_crUVzPCqsX_FYb7BO0,7860 +click/core.py,sha256=mz87bYEKzIoNYEa56BFAiOJnvt1Y0L-i7wD4_ZecieE,112782 +click/decorators.py,sha256=yo3zvzgUm5q7h5CXjyV6q3h_PJAiUaem178zXwdWUFI,16350 +click/exceptions.py,sha256=7gDaLGuFZBeCNwY9ERMsF2-Z3R9Fvq09Zc6IZSKjseo,9167 +click/formatting.py,sha256=Frf0-5W33-loyY_i9qrwXR8-STnW3m5gvyxLVUdyxyk,9706 +click/globals.py,sha256=TP-qM88STzc7f127h35TD_v920FgfOD2EwzqA0oE8XU,1961 +click/parser.py,sha256=cAEt1uQR8gq3-S9ysqbVU-fdAZNvilxw4ReJ_T1OQMk,19044 +click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +click/shell_completion.py,sha256=qOp_BeC9esEOSZKyu5G7RIxEUaLsXUX-mTb7hB1r4QY,18018 +click/termui.py,sha256=ACBQVOvFCTSqtD5VREeCAdRtlHd-Imla-Lte4wSfMjA,28355 +click/testing.py,sha256=ptpMYgRY7dVfE3UDgkgwayu9ePw98sQI3D7zZXiCpj4,16063 +click/types.py,sha256=rEb1aZSQKq3ciCMmjpG2Uva9vk498XRL7ThrcK2GRss,35805 +click/utils.py,sha256=33D6E7poH_nrKB-xr-UyDEXnxOcCiQqxuRLtrqeVv6o,18682 diff --git a/.venv/Lib/site-packages/click-8.1.3.dist-info/WHEEL b/.venv/Lib/site-packages/click-8.1.3.dist-info/WHEEL new file mode 100644 index 000000000..becc9a66e --- /dev/null +++ b/.venv/Lib/site-packages/click-8.1.3.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/.venv/Lib/site-packages/click-8.1.3.dist-info/top_level.txt b/.venv/Lib/site-packages/click-8.1.3.dist-info/top_level.txt new file mode 100644 index 000000000..dca9a9096 --- /dev/null +++ b/.venv/Lib/site-packages/click-8.1.3.dist-info/top_level.txt @@ -0,0 +1 @@ +click diff --git a/.venv/Lib/site-packages/click/__init__.py b/.venv/Lib/site-packages/click/__init__.py new file mode 100644 index 000000000..e3ef423b6 --- /dev/null +++ b/.venv/Lib/site-packages/click/__init__.py @@ -0,0 +1,73 @@ +""" +Click is a simple Python module inspired by the stdlib optparse to make +writing command line scripts fun. Unlike other modules, it's based +around a simple API that does not come with too much magic and is +composable. +""" +from .core import Argument as Argument +from .core import BaseCommand as BaseCommand +from .core import Command as Command +from .core import CommandCollection as CommandCollection +from .core import Context as Context +from .core import Group as Group +from .core import MultiCommand as MultiCommand +from .core import Option as Option +from .core import Parameter as Parameter +from .decorators import argument as argument +from .decorators import command as command +from .decorators import confirmation_option as confirmation_option +from .decorators import group as group +from .decorators import help_option as help_option +from .decorators import make_pass_decorator as make_pass_decorator +from .decorators import option as option +from .decorators import pass_context as pass_context +from .decorators import pass_obj as pass_obj +from .decorators import password_option as password_option +from .decorators import version_option as version_option +from .exceptions import Abort as Abort +from .exceptions import BadArgumentUsage as BadArgumentUsage +from .exceptions import BadOptionUsage as BadOptionUsage +from .exceptions import BadParameter as BadParameter +from .exceptions import ClickException as ClickException +from .exceptions import FileError as FileError +from .exceptions import MissingParameter as MissingParameter +from .exceptions import NoSuchOption as NoSuchOption +from .exceptions import UsageError as UsageError +from .formatting import HelpFormatter as HelpFormatter +from .formatting import wrap_text as wrap_text +from .globals import get_current_context as get_current_context +from .parser import OptionParser as OptionParser +from .termui import clear as clear +from .termui import confirm as confirm +from .termui import echo_via_pager as echo_via_pager +from .termui import edit as edit +from .termui import getchar as getchar +from .termui import launch as launch +from .termui import pause as pause +from .termui import progressbar as progressbar +from .termui import prompt as prompt +from .termui import secho as secho +from .termui import style as style +from .termui import unstyle as unstyle +from .types import BOOL as BOOL +from .types import Choice as Choice +from .types import DateTime as DateTime +from .types import File as File +from .types import FLOAT as FLOAT +from .types import FloatRange as FloatRange +from .types import INT as INT +from .types import IntRange as IntRange +from .types import ParamType as ParamType +from .types import Path as Path +from .types import STRING as STRING +from .types import Tuple as Tuple +from .types import UNPROCESSED as UNPROCESSED +from .types import UUID as UUID +from .utils import echo as echo +from .utils import format_filename as format_filename +from .utils import get_app_dir as get_app_dir +from .utils import get_binary_stream as get_binary_stream +from .utils import get_text_stream as get_text_stream +from .utils import open_file as open_file + +__version__ = "8.1.3" diff --git a/.venv/Lib/site-packages/click/__pycache__/__init__.cpython-311.pyc b/.venv/Lib/site-packages/click/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a4f91983489718ce8a7f9a29740cf5010589f71e GIT binary patch literal 3693 zcma)-OH&(3630uR7m|1x;|DgT4Yn~4iKj7O43=cDnehN&ASR-Qh@Mt=Tk4@-QQfkK zIqkRD53q-gjo1&<#}1t~Vo!T>#N2$^%oGn-NQZ%pzkZcnm06ix-Tlx0{v3n9Z~yq! zs1z9cFAlE$dM@G5v0ldh&J4zxkuZAfgww-&63D&4y}Xw=37q6f;uLU-r-;+QX`Uv| z0B3lHI18NRS>it6KHf*11J3arao)~51zsR70Qd8L;(p)(K0rJGJje%$2Z4w95b+T3 zFdrr!2EN5_5#ItH;UmN&z_$}iz;k?#_!;m#pC_IMF7hJrbKnv$5zhcG@CD*o z;6=VjJO{kQmx$+qm-#Yr5qO2K5SM^g`6}^({lZz}Ys8DdFZoO2CE#_wPP`1f!8eFk zfH(Oj@hb2u{)+eo@D|@9UITv3UlYFs-saoH>%cpFhj;_{4Sz$t30&r7;#a^GULoEB zuJS7JYx}LU%Xf*lf%o_x@ec4i{*L$!@O%EAxD33{_lYaOKky%btNcgf?J=9#{iBtu z+LnHl(1ncL1@@kP4WED*F<0{p{F?7 zxtaSStk81nitag%<{FA^xiDE5mLCSnr>0v{PF>qNHx&<}h|B1~ykdpZfl|`~)5vMU zYr@Lwjg*h}A*B{7hGzzf>xCHHRK8eY1JXj?rrv<$bxT(;qZQ=fy6**A%{EK9|0Uop zFq3Fy%c9{HiS0zG`epQd!?gVy{|L5L^|c^S z4O91o7J3*weZ8C z!8ZWDc6nEx0(ibJbAXP|?(e#JRZ8EUWt+P~&_;)TvVs6k#rI1J2i`HJ3l* zY-!NWI?YO&hJ}@9AgJD;`Dt5gx_SegDPL;_*n_+;yt*)hpw^xNL&v8R5nx1|8iW@% zPR%skD@;}n4?ln_U2S-lju*3Uwa`4V9ONYS2!2z09}deW0J%Ne)54FMOKtDnKR{=8 z-@SIV&(_I>Ps@+A5cilqKKZzR@D2l=G~vkw$e$h@eLSr09v|<%g<tQV zI;(zy{4ShTT!Agsd|x#z?AS04YnH2t3pEIZsX5>rL?_;Y8&{v_n=ZxqBeh;yDy3gK=BVi6rn zD9b1-D61$hP}WdhqO7BAplqVNLfJxj4bniP=U@F7 z`x9L3+b`A4vr~9#g0uHp&8lfh9|!-2^YFDdkw|>) zNhOkB8A^dArX%+3dyCn8BwNg$M6$(fJ(8{493^6s#jF&`7PHAnwwOJSWb3w{*@#IN zvq~geEEfd@#%wu~t=p>3?5h!ztlNGzBPLn5{zy%x{cJ@{vTm!S)UcCob2_^!g@r7! zTmr>ejF@CGTZ?4tcE5HaCRr>8ftcOyX=m-7bxB7BPENNw*m({+&rfGJ{>rM(IGuZ* zh?rzCn~G$M89Ysr#qtt}5VOaTY%!aQWQ*B&BwM%0GZB-lTdvL>c4jX|OtNlqq{69+ l7ZH;zmV-ddm~BL|#qtt}5X&V%MgJKX{aYUY#Sy%<{tvNDKIi}d literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/click/__pycache__/_compat.cpython-311.pyc b/.venv/Lib/site-packages/click/__pycache__/_compat.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..83c6cb23cee452babdace0e33659f4c4b7cd0ad3 GIT binary patch literal 28456 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/click/__pycache__/_textwrap.cpython-311.pyc b/.venv/Lib/site-packages/click/__pycache__/_textwrap.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be1923f3d2c6432005c6305cc178df69d2c6b6cc GIT binary patch literal 2654 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/click/__pycache__/core.cpython-311.pyc b/.venv/Lib/site-packages/click/__pycache__/core.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..279c0f2007e58f848e2e6f2946814e7da1f2161d GIT binary patch literal 140788 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 JG-0aI{{t1zpsWA@ literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/click/__pycache__/exceptions.cpython-311.pyc b/.venv/Lib/site-packages/click/__pycache__/exceptions.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f78b29dad8a6dc8157652926281e3718f59dfca6 GIT binary patch literal 16074 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 kt0Br8;)+h)7e;OHSO2mt3lN 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­pp0tgy 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/click/__pycache__/globals.cpython-311.pyc b/.venv/Lib/site-packages/click/__pycache__/globals.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4abc6d12381d67bbbfa913e40602d2b6e3fce875 GIT binary patch literal 3381 zcmb7GO>7&-6`uVeMNyO~Df)3-M;*5g3_2DQt0`O%{c{wnQQ|VGrJ^vaf*kG)#kH5a z?Cg+~1f^9B9aO-F-rP$80Zkn{$sq`O@S&I9a-<9b78VE~pvb{D6}|+%v~Om)G^wNw zI@oh#^Q7X472?#OrZZGa6cQTJ5i{-r%SRC#Dh$Ieb*h}A&(TSm+=(6I85!W2qH&g@ z378v=#L(gAqb{nLH1$;pAo-hijqbz>BXpXkcg(^GIzz|co2Dn}c>hT(_3WfU9r{;5 zhY652Mzv*>dH%7~EuYbXnB!T*c?=FjFdAC$T*21GVi5Ojhq>bExM105{^}c~Y?sNZ zS7+|B*WeagU37?lbM9BHJa@TXpId1NkK4pq%{H0aT)k?SSA9@ru1>6*WR3Z&mSbBt zUtV*(GH8~qZv@Y+F;TP{oP+8`E3}25fMZACeIoN^8y%WM+Y3*ii?ZLOJ(pR)6`jk|E-N4-laGXE9!>+CH|3i^~i*d`2L*|Co$0JlHGWV3xoY?$t1HH(FK3StJsq5?u2*!*;C>!L~&x&4Gk;iLjdt4p5rq zDh=1lmFmRzqrjIiWtPVYBvB+!G6~yrvF$5Cb#B)Px19~Cb*16pipO!4Idw=+>^H2c zG^8t)eg*KBtU+rkHqDrwpvvrME{;NSr- zh91Z!m6#O|*BgHI>o_jpT#bopuGGDrS>J+7Q|kA4S4cLCo1iw0A7$>&RF!?$mIkpZFyw-4qU1L``_joC*_!QDS{x`JEGb=JZ zq-vlLfmlKY3?^efGZbhdFfHPXAYN4P7Q}o3m=T<~ECjd94H1eDl1naS>*}Z=)qikC zSBMp8%$JuA<71b83MTzsAlv9@){MQSeV!h>-Tb5d*Xj39-z#^{T-;C3chd9i#Qc|^ zr%wI(&GyK-BcuagKRrlK9U*NPHc!m9zx~?o9c;j{5}>dhlVPKS$MrC&ljGNd%w zNubo&?yLSJD0A!VIrPE!ow^a<-gaU^Z)s8@E-!aB5Sd} z`QkNJ^P1omc?E@6#|~>Uz#@r=aw>F4K4U0fD8~dw-K&R{NfjUo^uY+s^=v*1GxPBJ z(lw#YS09;^56#JabGliqVrzJBU#KlG(>JXR65DbedXN1bJ3~4aBa{Zkv#f3MnEWEXp|5-2|@)qIO zkGZmX_<=4MfGCvS@QCmhLY8vJBUHI1Fw36j1c|rnvZNA6T{AB8P8okJJD(+1e4#z~91fq@o%+Mf z?V0WPQ5@;U&Z#3^(-MH7{p4Q;(o@k=;uzbWskra`_T$Y5na<0v|IfWs+Sm~SA~(V3 zlkvZuda%^FxTr?Q$t$|{18GA)N$T2+oa-maQ7IM3-uU~c?!6ARM2#N&;_rpe%+8N~ Lu15crsJ!_Po7py8 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/click/__pycache__/parser.cpython-311.pyc b/.venv/Lib/site-packages/click/__pycache__/parser.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4d686c3f4acfe7bc2b695cc6a962e8cb7ddb1be3 GIT binary patch literal 23131 zcmc(Hdu$tbp5F|~q4*RjiJ~N1vPTbFmK-aQUrB7ou`F4BBvInElT8$FC7Ls`Xj7yz zr2J5*uCnL5rCnV^2g;e-_1^Ke-mG%*_S7P1eZ`^89$Fy4-2tS)s|mI)ggXSd1^NdA z@AZNJMf>^wh8)h&(sutTIvV}v_kRDr?;n5eb~`vc-~P))OcYYv-dEaMiQ;w)idMi{p;zW{&Tcpdy!sV;1rv5(uC-v+;9+`;^I z_?_cU=6AsF8h7!WY`W~OG_AC=mg>hnsKpuf&NPfSvfM8Co5q`%-wnTSyqWpy;rEZX z@SKV2X|2>Fc|PGe?lb(W&v+Zsw|s)YXO$>!e5>R|nf6MA+|gF?a#DjKWt%Rg5h>d% z84bBimqjhUqb8-Zno_N+>XS@U=4zehNCwN&dv9UZ8%6*+fEZRI*Q?uA9#f?PXI+(}N_dXtmdKf#Xq4FBpg z?qew(NZD4C(!f%-BSox9>18RMNa?Cc*(I6Iaedu^!)A_ioSzQG#F?lx7na3XJfOs7 zNsP|L#Xw992b4>4_=Xq|gVEU=;%p!mm&GY1IwQuXDYFy~UF?lHqOIaGyAp_$pRJR?Wq zRM(6ciipGEQ1FTvji5u*p-a=UB8KIwa#-9o6;&Le2znn0%3}P+tSn9kBIsS@(lg?; z9G(@CVI~ldBSJ(1%7@YXOjMEk1{|0HS)2_AA|fUt9xZp4rLxSFO&v8_ltm0g5#ym5 zxm;3_12J?dPSc1tAWEUBDP%;y%d<)?(r~qTs+mFuwM#RDaiW0${ws9^F?ksH-hu0^ zEBokskyeKmKvtBfBF@OMSm2Tzb6k=mvJ#->qXxCcP@FQWt0iJ?W8x(_9+$7jX;#oN z@lrG@VbnAX2Nj*c+{Q(99p-3Iu{k-0(W=wWYQTEOV`6lw+RQa2gi0gg#T(*DMZOeO zZisITh~Et;YIkM=p-3G6vgAMx>d+fE;?tP7bJ3~zH5&40bS@$V;-P3{KxBIovl0%? zglIrmm0(oDmWW^zVy7tsvp1+i*p&+F?B3^|8{7luU~S_A;!rp&vP`rMQ55@dz*usx zTJkq_Xv0c=MTc{&k1q<6{N9`lPhELt;k8A|{$CO7M1=QvKpIjm&C!m2lU59I^@w|Y zmd0F(ag9aK%>}2`NaS#^gcG#VRB5FG`0IwF5n4rfty*^b8v!LSBgbW>$iG#z;QYpl zjtG4wVzY9vXjNpK$VgCwEa;nne>47{WD)yA?uWt;t#`S&2Jt!W7H7l(w+*QY-k7?; zU*Z;k-)>talVp}Gaa~)NHGkZS7Ryf+Voq6-)+t^RZn|y@310b26L$;Wn)=NN^CG|G zO_(L?6;_|JJz>gNDz)jqRKB+N#@cu;@&~LYR$h5CDI~cmlT>%p7I#)_N|=qMMmQq| zT(I1-e&9=3GP+S!OB?g@+-ALvd#Ys;7GsOX5PE$Wy|!Ip1(XA5-4k!9mX_?s{6FC1 zP1V$d$(VZEx>=8;nz={c`PIKfYX|jxt)1b7>6Y~fn!Chdr!?!^y=9fG^N5i6-__w= zV{fQ*H5b*RZ>zTN@s?`+wf&ePEawRPKDP47&{e=D0`WK+fr~(OfL%Bi>@)&s6HYKD zvO^=%p$Scef($Ojo^gnHLU8~RIzK6|SQ(|-XGvBF zGtjiW20TGSzzok|W&qKrLg6r`flbcjSTrI}4zQeKMLsz1jLQQf1UBD&>w8Kg7BQ%U zI2@fu+Oba(a6abma(3<(zvxSF8HAsHj3?|IhkW|lv;wvHy1BRxZuD>psPT6|r=R1l zao5f7aM$=x`LRB8v2HesWuA%`&F~Z*r)dRMm~2vfsJ&>3VY*@jjl{)o-x)r1;Z0zg z*o9Mpi=m5w3(;9QaxOZj1mz2(;Xv%lp6|*R_YBR>?m0gfk1C-+_`(3T=hX|ZhAv*f zq|19~0})QY5G0D{Sq3-5Vd>xbyz<`&n<-Izn?F&E2`Sd@WV~&0|kniR109Rj1I@lG>lz zUos>1n{U2}c~RZ(H1FYl)U=2Dh2yaK-}8sf3PC%=vJom_%eE7qk4<+00utQ!+zUJa zvFTO~5WQnssz1kl$|>8BxzAEG4Ln!mCzN)C6lyL;OCySli^^7bzI7Z4hhp(ybY}MG zytwi3t2xe7`A#^Pf~-8SKG)|`2tyY6c+sZf+CW$#XkD}hX0fSXra;c)v=K(1iFhRNIRYe5?-6B%QEh$Jk61UHZ{0&mnn` z^4-Oj$5JhF|Io_08dAPnhnEg7jy!Jgr{;4FUHOKt#WRJG(Z%D1c5!i}WT_KcQ+rAr zK0h0}f94nO-G7Y*Hg_61XLE`33+)B3KV?Ow-mbj2D=Dlyy~&pfE+4+Bq1%U&hYGIx z4^Q7dotjEbrO)39FNbrk?!2oz%ie;!F?II#JIQwnm1R+v;%9R!Z~k%OegdJKcYofy zKRHygab926v%TPLxNHB&e#g1&OgY!p%0HIVLwBZ^r*p3DdDr$Vd#hD@no#Vqe|uIu zobw;a`;TP3N4{$Er<6O-FF&6gsdP}f_4?B5$=6GJDkCfH=WMQQUCZO9*0k@=;pM|g zQ*!?;Tfx(iv^;L>%yebWuMGY1+nMpq`2B%g+hD$JkaDCtZ@rMjz;D%mg*j-v_2SZt zA4}=|cP=kq&N{`cMO3=5Kt*$OHf}gBw80tW^;3B6;;2Y9m~nwm@EN2%{TLycVv$S< z&@BY{NV1^Et_i+OB>{S(eq$QK5~t72>fl)|PsR6H#@LZBa=)VULNsV776=3F^qCae zf<=L0I28_x>SndaX2YTQ1ct6Wk1R9zk4?i_7n%T^znOj zSn#ZEdja#`oeHEbrYOX#o`7k5M{P$!7T0miaOF6ReZsN2Weg(HDs4sv7>eRZcrD%GOAnhvtW5?lOdg~mE@27%!|3KD% z5L1?PJZ{{Y9=Kkv{zeht5YmrEc+kC5HGnpS)j3Njy2j731hLxNQ4p@5V2HTq&Lp!pQ%77EQY33`c5qk zdMgwm+!hA!HXxq9grx=7f1ii99U zS~5~ZBSXU_XyOqSQXT+{b^7nq5%4Tj{*u0*uautU#jKEBJz7L7#)R_bE z$~vi%mJE@Pod;+Vhk|7lng9>9e{i;u8bfUqwPaOFP}(n?R+UGkzs*y{uB<#v2C2t zu=pzdtvfs)?!LV{HI*4j?#?;-@{Yd6;lkGKi^F+KYoWPiarov~!QomQCRDwx(9DRl zZA77MOP&Di{P4`}GpV_pt0V8~$g-D+wQb*gMOfM*AgAWoIJ@gZ$8ASy-|~w&TSwm3 zk*&NXJ92?)D7iS7XYovoD3M=m8M1M|wDk-yQN?Wr&Oo_q<NZWW$#s(5kZQiHo$+ejQ!dGIQy90) z4#_Dy!Nj|6T8wCN+$FhXL8_NLl2hU#n)O2H>Xvw%?nZ?~=Vkn6j$XW6gp5d$RbsDb z0ep=WEs`9IgW?MkTcivie^DTYDjp;ft@6<52wpvD1w2zJ;E75aqlc?dFRno!u127c z;3hPf$Kc?9Sg4EJwQ9IToe^F!L}XjACv34Mz2HLP6Lml4B-2l7Xzw2Y#b4H1*jQ|l zut_>my0Jap$ducRsgk8kats()_Zp#umTN2eq75yht*jOWPwjXC>u;l!hChDWQoqfp zjblMe|1n`%G)V$sBCLzH3JD8Bj!G{R0z#U|C}BmYqW%GCfRLt|A@;J*IyT>PI&u{_ zUjjq}d=`V#0B=D6A|{r_h9lm4*SCBhgJ~+^CB(ol%6;`k=LEQNg^^Vd@J)oHkxN8k z#fs*b3?4=A+Q-TmIj7G}9C2wmj zY-vwgmOPJJxBf`DC&24oZ)z!Vc6&c_lEaVNcVvP;8oM`k>$T))>O`T5m{#{2{A0hE z?Hv2k3`c!){@3&V*R$T&3oh@{YmZzVYp#y;ROalxP|me0@7k4h?RpFv^5Cuam)=hY z)<8LWw*PE+Mfl@0_s^_${`B?C>jkeb?-d_;d)K_ZE9RW{nY{OzEPL0zzGcrN@6I*v z&P*)l-JSRD&U$wv|FZj$w{y+gnc121_T{~OS@y0w8l+Hr) z7JM9)Pm>=ZTM~ba?0Q-tLbMTsDkN?oR-t-gB>pPxDAO3I@Uuu|3*5)E)y3z#G}m-c z$~ejy4_uLB6KvV$8_Nr$i~A+zC;oepTlX|Ay`SASnDq>1ZG&ph-bM=0X&l0$q6^Yy zqDszDD5!xG&s*`Bvo#hee^xK#2E?Kj1FX1%hbxKA)iefTCV`a7yqBMuA7ls;1xM<=!a0A zg+W6M&k$y7z^o6ItISp&Yc z<77b9F~$x+(aFH%1jEfLRp(O0G-?!K?YT(23Rma7bCD~N=rz#B47ZED-}1eE4i!FD zVITp?q5}X{lBWW5;ka708G0TS#0pUb@=z6wn%TKi=(H#o;21f#x>+R()n07AzI^`5 z;r~oII~iOoI6X^;)4glX&aAVu(9@SZv2-RCU%ruZb!J_i1$V>JyXn`~+a<1p{uIC=Po?ml4|4_)ej^iEQY|nNaUA27f#7BK|jW6dLU(UK-F4){l&PTQ_Yql-v{r6tT*?RJ}o^0i1 z!01!6O0bOqBLdk(p!u4Z06Lsd6|eBSCMMpSgNTBqDBZMxwsU133Ai$@C_NNshH|oK z9*W#h-eFm=9J8_#zfrVYj7G!CyNFb#$RSas3I|Ch$!JFA{1HO2{|;wS`vXPY-CJn( z7rJ{(p6voK8Ju-@TS=gRmGgL)E~lH8qNO?t+p1wZg&kZ&@i(_P`d5!v~aEuMok;NGo<~i!P%1hsrt_mGB|*D5ysh8YU*e zD=;yHL{<8pQHX?W*~92Q4XF``QpG;zYSpaWPc166AOftKRF;32c}uo4=Nl@W(@3fR zf-*7MjF9-0DU32{QA<;3ut@nHwL?0WF$2=pIF~=f2x@7JD{Kywc!FOvo#CKR)Q~XL zd8V77ach;LMi9LKwXL4tsYRJ(#AKErNs0_XxoN(_T2KzhE87bl*7HD8jf!+rq@kfV zJra5#7*U$Bw~RkRd+MVpnju2Hto5e4T|clTc&V;D0uzmZkv7^^MJcThgdBl5iC$(; zM&lVOG4$29W9%7>wTRlYsgTbgm!q9V@{T72rC#B9wuaxcQEz@>k@&Z`yF9oVJ1cKe z%QJxXsYxL_Eah1^F{-4z<-WBaA)Auxv&zx=Zf)b0QB_sxq-FYBD&Ga?@9_t{OUpsL z>A=d+%IP$}a$5aUV^u&xZO!*qY8KxoFx{yvh>RMgAk;4lqRL97^-IkAmoLYRxwFsPAK6i#qPi0eo{U z2lH@!2lKvz5aoD$KQX6I{K#?7vF7Q@db$d&?I|H86dL^L&X2aFwmkOleC%t^`d`lZ zj^%yF9{EnL`A!x(I`6%+B0acVGIPzR_^&xrv;WuRd~LS0H2#`{0|8J&V+nE{>QdvH zb8FVQHDkGNyYGQoe;Zg>Q$@v@n$L_*e)c#5)GcX?qCq2eKtDT?s zKRoyOvn=psH~Z8&juv6ZIB+9EFnjWAg{i=LQ?6Xn7S{ zQFZ6grm3a37~&%5AE-G3rTRT$5eCzNdsCTn_pXreb8tmspG_TgA*njULRPGBp7dbC z^$R&}mO3S~Y^f>@BukarkObJCS{OBBEek`tRH_3dG^8QhbS0enx(q3}GZ8l+ho5QZy1YB+KwD8HKjzvwK7ZEo}x?TzGyc#4%zBN zRUzIii)F^4urVTCLj=m0AS^-3cAwDxfSnA%LY1s-p|&B5N2XR`Ma%V+&6Fw@LIa|B zI^N4ncV%X06PP05A=*?6kp}1@sitDArhpiOF(pnqQ$}5dDKDBr6to~yAv8Gj#%We# z#oR}=CJiGKnMA;Jh`PmUl0u3cq|#7%k#>npam$9ds)Z;U8MIf|l)x-mOOcuBjp$t2 zPKb3{wf+q#YAvv0lq0banPs6)Z3HL=z*HU$6lA1BL$xT&`cbtH*6fU#^%9vLX=xZ4 z#Hh9Q!ZDawqA6AlnG2&)MJ#jmF)|4zq+ixIL34blyaKR&Qf*fcu^}Fs{HM%5XJA;h z#GDkbF#}#^3al(36Nl&8RuT76+#XJ&u;T`In%(A#Igb5-V2 zIfEuQm8ct3NW=%zDm?jbaDIqYhfOLk@i%Rx3iAEBGwemrO?nsP@ZVRkDZ(t&Yh_RpzK>(#szwCkfn4PBJOvB#a`pGBmPD zC?6+beb3q};{p+#iNr%wD)dng3dYI6FB3Y#Qa+|aMFKPo3}QA^GgZulcHuyUN-Ef) zoCf}pmaPf@PY%H$qf2JJ*RsGHx7aP6(B8;H!=kShG7e%taWH8+Fc1Js7RFyPr4ds{ z(B>A!MU}1UL|}fm;iy7aRR#w-Hd8bI+fN6W__lArWO`mw-_@p%-RWRv|NR%r+L}s& zN^Y8KlwD(eHdT6;LOn(6+$^ph$jX}tDBmIHpObTroDbpj*>wV%S15J^rC8CbE(|l< zi4pTZNmERZstxXd}x6;=Xojbc?rg74J|NzI-l9U zYJDhwc_7)L_S8ZlMsJzt|8*H;RE(5CPk~fm*4)1dcKm-lX*dvU z&yYM3CdJAfe3|e;l|jZ4G>RLFF4``YQO&nKwP7krM`+8C>;^l=%h}yajz_k(HCx+H zc4hXhoPXGy-STp7%gcGVwqtqQv25j47m+l5MK{SkfhGZUaSArJks}d@@m@%+2yX#K zAe&iU*V^sFD2vN%jDu=!CqS3h1EVetr*IsMx^PbsA~Fphec;lEsyHde|G;R-Wvb#P z2;r(YNvC_7B37IajAK?A;ZU`N*KIPD7Oz|bn4H|D3aOr^OsKehQ2jafQs7yF9Wg-T^=*zPs24f{tmz7&SM6Y0}6*|IH?ePt?a1MqIS<5x>xSB9Zhl`K_%&Hr?hK}_4irI6? zB-s5hFnHwZUvu@Z9LTu_^RB_HYmmkDuDN$LU2%o zovegqK}ZOji0n-Xom>S_25{mt4OT#e-31z#uL`?Brtnq1r!3w!P&PCaM%lEpiC}b% zo#f&qvQ!_?E{+QA!mCCx*N|dhDmoD{|GWVZZ@fu2qFM-`#I~RY5G}nU>bp7wnPi<7 zR7n*pGwD~@F8&?lXQ-lRmtkiO*#hA66e9bq>ejvhKWrV@$zY(|9Fkz5NMVAQjQS{x zukRr|-~C(k{%z{%B62TskNsVw1%4&HCHJ87{tZ`<1ki4&HNQPUKwuc~^gy zz3cuhkU={O{#N=V@yF)Fu%ij$vmJdAeI#zUx`4{h^`VXFjoSNc;GXD=l%HB01(lUa zs@R>FXkQ`xlm&hDoLq&mF;iSoFM*?g;h3*df8`50=czp%c^PL$>x;4#W6>~PM#EE; z8t7ZwTj0qK!we7?`P2i6fvNU9v61O!a`k5v!_E;b{^{T;|BM{!5CAvZldTldPYxrX z-P$>b!U|1Uq6D^qcfeP);%+w7=@m5#?OEkMOTa$GwHPDeqx=|2^E>}98x`#k3Z-Kn zTSEcJo$H&HAoz9LTMCUW%e(JB`_Z$R&RkvoN!(r3gp z73(WJs%o}nAi8N)*pawbJ`&hSh*F=c0AdZADI4 zHCD;22WBI2Zq$+{_^JqZ!J4q@w)266>4U8ao#pSwTY96-i9@vEMn>PPxR#5NSDA%{ zx(Ky2Xt?ak>#v|nwK`)`<2>~wcxZ<)o1fudeT=j816VvS)FrGLS0!ElP1K=ZH7JW6 zCaZdwV4U6no1qCZ>6a%U^bJnSF~CW`q>u;6J5Uc7|E?4=DICId8*>QE3(HRM=jRIz~;BH{WhN+H3~2)F0A; zCT$Xv&f$uXv>eGgd+-(*bp--Td)M3dWZUDcO?FV6p` zx3i67xyG@4<5<=;w%*XZye(tSH}rr-b~fal9VO0dZ-cbYyDjVK)1TnMOeE($koO+Q zdJn*8^O0|0&4=qTtD_H3EpB6mX~wQ$MVg`9yOm_ zYd-nqxoq>vT=Us{^I4$Brh1^qrh1Tl?s~Mx)UCGq59@E&r{>b~Ms`gMI0orZS00VC zzK)GWS8f)}5)L%X4s<5k3j!|ASP=&-rN7e!n(J?2KCW$M;0^)zm0%eD6UcL`bf9t5 zLcXW70L4Ash$AQr>oK^)q8yI)L6DK31@{^#R zXuYq!N(3NeuX1wA8wrd4CVVZAdWF@g>;U&i=Yl;MN5!ZA;(`*7(HLgZI72YS5I`ev zo0xFe5_aHP%$p8CIU-n_1xLcZ3FvSZzOSj3~Vx=W( zM$_2oN0_i0fgJ4zV~lESqEQ2NW234(n`i>S90F12)hjlhs<=;;ok>VjexDp70aPIL zF8LVIpaCJ}Ur`*v7)CD?EtjLA2&@VixFH&WK^oYk$8qtR52-fio?4ZGDLAcOmaD=c z0_+tygs&=r^Oix8reK)w*a#MB$v-1t^dTHj7am{IQgFGGJkbkhm;HbvFj)7jH#S%9 z8;_l!ik3VkQo;jHDtnAHrGM-i6=dHQML;1!-kf}AdEl)gZ-nG`eYo#gIyeHqh zCpn6GQw_I9lSAud({6De#P#cZ(*Qt5Lr1~a{m9q9=IdYCoAV9ieFItFK*84z${ZBQ z$b(Z^|ACzUK;BQ_s^DqPdpb*;!`(rujpmPI>3w&uFJJ%YNa{$z*S7r1Bj3(7-_Fc? zE8Q!Bm5VDEAN1yYd-J}%S>IklZ?BJBjWeuK#$x|2QJ>=3FQ8t`phHOA^OXUM;S78EI5>sx%<8`(zl%Ko=1r zBB1re&p;-Q3Igi0V9{Hzfi9u_%pT+RPgu&};uK120I*6ADK`CG!v!JoH~PCb30@Dx zhzi4vMFTk4mEy1Q0D1snHz$N(U%ak2y~KgM>H zXA)L0JQh7N0T9x_B^aKqhMBAZDCnbwDt>C7VBc4r^Nqo$R6~Jbc6Y|B1SaluR%?(z z)$03bTtx^Pp33_YP$0y7xP`Mr1prkFOM!VXG~6Vd(`3p675&5p*(zpgU}e-_6B$r$ z(3puXXUr3*G7|dg0N-f@iwzS~;lQN{rioICFqQHm6v-&BB7PUD@}pL&Ner=CN-H_L z;6TC3pya=!2nP5VQO4RLQmkl)?OuF>SrZZcP= zQ9yywge-K$TYR(s*VeVmfn;okj~Z(I7tFS=F8SP~F}49(lp7t`;hFD}29IiKJ0 zeAY)VZ1B?dJ7ddZnX>?aS>H~QRP<9f*QxeD^85?W3ZHB3&$qJ3uY7GJ^vFzQ<}y?H zEql}!V6I0jU3xVAW_mR1?Oq2~aH(Pn4L)FIX$=|d`6rk;`r$v2YmheKylmO*nmEA+ zPUz=ZJn-k>w;18xo?4I>OvQT$W4rr&^o9b8WB&jnO@ zI&hY4Abn_;KlK2D)r_U`vnuGfCd?q=JRlUoY4&6^f~*ol-&z8$Qd8w_Hhz@gTmB{W zw2|c3`# zvy~U3=B*{J-VSA+=HS{ullH3#QhwWWSr5HTys=}=yCV~X2-`cD_YP*ggX%AQSaJW3 zQ6VaFUnfDJioeq_{ZD$RKkQNJKwI=vF)bM8pS27%a=&aGJpPRNFRWeU?&je#^LOPE zGAN61`r2xY0E=}K6H+udF`+XfeTQ-r9@ZI@Mkx3PhJ?79a#L(i0WClyGuefzgnv7 z`ny?vQVq*~sHV@}do%6GH*{yt-hXRl`2M>v*xmVXdw%cf zY{Tii{Y*(fesJIhr^ha|t-OlMoew+lN8P5zRZ zzPtKh@w@MVM-3f&m3`TukXqu5&XJwMD4!WFar9kvsoyVr>URV84ZcTcE^OUaGShe0 zfckxYn0;w3no9ywN}SPomER`xWI!_GvvPrb9!l)9siR5)X-oF?DZj+0Xob}p>ASiq z;0#7#0LbiAV(fQ{6bqtN5e{LZqC>tOlvR1DLf}^=Gzi=>ZCcTN{+%~YObnkoG5pHu zv6ICHwepFwSsvMBnQ+_F5`>ai)mD?{U$s|bN9ha&>&f{MoMPR1nAE)mD|=E>!775O zAeBF(^qO=07ZmpaIX&diIaZz{=Xr9DkaLn8c9Pk-B-;{oI_S>Jx3(kdRj;GUUn2-0 z%f-IHfd${d^CeRwk4-|(0LM3FxkmLZa2;9WTj0d3@hx!eS>wCT?aCV80=F}3d<$Gp z*7z2aI z(s-J`SC=v4?2fPUpF1Az``nY?aqNqptO$1SWZr%1%g(>rnLT^{uXbnMZ{~%!N&>1X zaYpAlZ{@e7_LVq%(u4P&2e)d@ypZ4e42!9C8ZG?6R1CZ?e=yTw`jCWQG8%J{VNHO2k9nsAKA+OY+!alWQS a{WUpig7>_I2L|5Q{hG!9dXrSP!~YLHMwXZW literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/click/__pycache__/shell_completion.cpython-311.pyc b/.venv/Lib/site-packages/click/__pycache__/shell_completion.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3039c0cf31ca27523cdf8855e83900f108e9fdc4 GIT binary patch literal 23580 zcmdsfdu$xnx!=sbU*z)rl*rMNBDs=CSr0oFB{`NU$&xHnwkX*#E#2j6XDF_;+U1>D z>OqmYys7WKw98&Ig#xpQ(lWWSLtm>X3*@3g5wtgL{|Jf{*d;dAVhRC7+x(HDf2<(q z!Z3=qzwgXrXO@)gBq&;RxIA;_ydU59o$odCld7r!hwIC~8WS%a=eYku55^VJBTtSx zIqoCwJSTD@pW;TfJ3q>^XUC`$cSp)~%{A)gIngP)Ql4wxQ7?{V0T%Zm9vls_xF7M*Xo$rFh*ynPv3M|5eJwm1X7Ny}=34D&E#g&@Ppp=lSL%!* zOZ9kaFrLO8twxj+!&1Figa2Cm*GY}zA+i2F*JzW2dzBL#-s8l^PaGWg8UD3vv{`H# zZ4sMCTg8^qHdd+?rP?Y=wX>Xd|v{AE%}u8%Js)xVlP&F^1>#RoH2c(0OH-8TUyc+xpjApT>RS9`w*J z@*`Yy-*2eWaFkcQm!)i0x|#hAj|4pXj>wm%u1V=E;=xzqiZqnDb}gP3spwE9O+^t6 zy*`!7Cd*l#Gn3h5CXF2b8*w>)P0C6#9>V6sNM=e-NJy$tCR535EG}P;DOow0zKk@N zl$gk<&O|Dy`V!fjl&PrxNjY;lmPT7@D3Q4~nL?Yf>v35PCex@nm7oq)k1S=UA;*m;$~dSc-VM}{3po&jONX*3#c>ep7qSSvL@F~^YSugBopXrJ z5zfKQcxSj7e#SB5{KSQp@ULC7z8RP3y2?;k?#f!mHsf2iv~852=d|{ z!7N12Q(83pH5)+Wt6QWwM7?p$gL^}g$20OZL79+JDM4RtEU$o6Av+-nmy_3}v@mq~ zq(HlZ4IT&t1YCoYwA%u9ZcxynLAWGgSA|48m6F5(TPb~O2ZdudvvOR(HZw?5gltBb zj4O0!<*DVdF*G`GEq+ysB{Z-b8?&`$g2$jR3?LCQ<7}kTO(`*zjbBPhLNd)#*raS# zt>9EqJAFMVXVL`!0$?r4+R0ADv%*9sB`W6VXiY53WPwOqN0#(K;jMUTiVYJ}v%vG% zm~bPRonS*PH)-}{X+i)RYFo6+m>b)*u`x@b7@MxSRvLN?3M1Kgc1ppRMTu5hx|z(f zZnfd6d~8@IFj74VLsXey7s#lOGwKF9#^r31;ameq1~!GEB!DEANMY~fD%6mhC}>6y z^~=>14^vP>K`jMzKB{guM7fdTtP8ZDs4i+z@gtG8pIu)jh6XR3S0q`va3X#wc`1G& zGbyDtQgY!qdcE5Jwsfig$mC@Ixv6Xh+m*U706@Kd;dJuS1tpo4`X}RwtMSW{askkk zxVoG5Y#IB&C3xzE&GhI8KLVz_4hkJp3s^DizAEwwBkSV`rB2MfW2b4S;`b&C^g z-j1BNiauLezv#k26~KY)7lWwhx8~xw4dH+Zh%V5TYPEXEgpiY2=~_Gr!gp4h zlqChor3i5={#<9MLEw#(BQD0XAP$!@Q(1--EOS6OHz6^k5T)@r4xe(#qyl1*y)`KT zlK|Suw3tl9vyz}pN(n%OPShsQdJ2ST7i)yN8XE((n?$ALI7Y*OKv1S8Co?jJr%YsS z5E+XLR7lW{Dj|*2kNN=mvu3oRX{7Lod?^X4Cf@=n(@#L)TRaVV$cURH3O6P|L=&)$JtO2SE1lN$CmS;GV#`4&SHXHmPt*dn_l&Q-=7s7KJC8PC4SsV|b(x{;?S3*us zvK0X}zMceaF&4c{9@xAHo%OXf&lGBMKo}yt#B?PZW<*TN5$uSzJ(2NbO2VUUAhaDs z&WLqjyOg%>3WzolS?s9ZTg4G{^#<`4gF<<;41i+*CS00Irn3DwIFdx&=or9WWzuEB zFJ@@PF(9kY)7Daw8_c!ct}`z0;1(a8J@g^ z0Q?X?!^IHOE^seg%;bS)oOoh<3+2wZ@Z{7BLf9JNKIMny2oi80xD+WhUNHulIA?|U z9Y(+9t%#|<7={g&FE-t5CkX>a#%ZcW69KiY=9=2)T?>I?Lkn(xtY zgS1pMuUJeC#A4Sn;#7*_p;+vXr{XC+#~X`@nFNykv6zy|WEDjDtm-_HzNI=rr&OQD zi^o$kNe1$B2tMUlPi*Y+HcF-78~9i5A(%7&N{$-0uf$Q%&DHLkJ6Q^Fja!OBcgY`c zZz*vI*26UmQzbV&dbn_1$xAUGhtw-e^$QuTV1TP{xU;x z>@0D(t?>8VEb`Pqn*a?v{$uRK_CB4$NU`y$bRw$sMTOf8y;2#lp2ErFBZs?tFQj`d zX*hZ&fyfU`<=w`&{@L{1B6tq{kc<~@n>9k32s3eX1?6EgazjL@RYRjN@Ga%#r z83DBk%*ymmN>z41MEMWtK|8+90c`AmQMa$^Vdvq#Znie%sf;ICqoB~{4wGmoJQtV^ z1S~tH!Anem;5cbQjR8%x23;e&zrI;c?>wF{1=qTa^g zm;=$kx8KShX}hsmMvTsum?$ai95xRsv#0@NY+?HPgl$6iPK=1;dF5T(R4xk9sL<1+ zvkbzX3LNPJPV~Jz9^DLAZe(P%wgFB0`i9P*J$r2UT>l<4ZCQT}Q>LwmVjD_yHex{= z2H01nTLPOUL!H~kv}SF{qXBA!p+ZCeE<_k4MK;FRaK4^&ndXa97 z2&1GNS7t+lk#21m_7-)3rnU?$vCfWorOoFSn~Vc22vHTGf44cP z%^G1W*4Jod+-zk7n$b!M{b?J4QZ~*OW33=cI^cpo?te>|N)yt7U3%t{3H|5UKrje) z-?Zpc z0%~c;&%yGUpmVEffgM2`aAZ7bMUwKFbeIl5LShIsSiHn!)OtYKGqZ$y7Mc~+#za6x z<1z+SK9B^Bu4=`kv}hTwz8ExB+Yx5MhCWk+rxyBjxryoggvhRlU^&Dv60;)qF$<|f z=r*dpyXT?+3?>*a510lW16*5HC594^pdkAL*2}f`UM$xl#H3?#(+(K?m&}`{x^J#6-Qd9qI&9#L$pik)UPiOjdgzncj-@dOXQr4$M`Yf=dfnpTvm;m== zUd-Hrrzi8gRaXGx3bX~1>x!whlssj90AzlLrqX{#38${~cfly)Mmf^yuuJmb$>^7} zDyN}^@IVXU5q%=5!UNDF1fj6^NuF_s7<|uV*Jh4ZA?Itgi`t}XN*Yq)BsE!ElYcApwYo$(ARK`Je95fB;3}?b zaW&EXMiQFd%ymhYNo+TD3Q){wT9}E9$n>(NAWRG;YsW?ffZ&=YUJ?4n#x&)jDZm@x zJ2n=zs~*0dzSyK%6*}7g>l$9R3CN8RBZ82g{;D8dq z9kgjXiG zH#9?H_Z3?N+^UML5!|YaTl(f*1z&59{g@D!07RP?X&u>gzk|p}T-K6z#f*!*2rb1G zS{imOQ;iK58GP+V(X6G+6_@c)VXNUq*9`vy*jRo@_7KnXo1_pUA;_>OX!v3t^56?_ z>WadpTTBsF#s;?cM8Gv}TvO!G^R)BA+dEY5OTJ&zc?S&%5wHVAibIwlxKCYTYI4;p zO8}RIq`Hrc44piwYamp=5+9eCa=@mC@YAqZ@^rI(i_DDwjCm^rOmp0CACD4J-pU?_(9@t_vL$EE%d(nAL@SDl5aR$XgE9XFNULw2Xf)4{_{mQZXGQs z+d5J+*cC3=EOYa$8z=I2X^|b%AH5ZqHDX2<3{W4UW`jh926ZB0;*FuTq?LSy!~jkG zOX@eB5;E1HL2H;gU~Fs`w25XCBo3sQ`=e`+q(GqHA3py>LPWc3G z<%CaphC>R?)KClQIFAmM=~nxOShD^bYA9U@7}|71?*376i%{6oUu@lax1;2B)dWhM z7Wg%FmkniT&DpvSB2u~To2$C)$LBPZ|JVh7`rp4HL&uaLU1p_5mrPz7q-*-#O~Bm1 zh=C2;GB&n-Y^-0&-hvTM+uyQ6;VGM3wt+!=Z)mO=mYLf&2;OkQ1P@wbT{Fx!&LJPh za>%4glwU(&*%oG%nr_%^JN}MJlEDW%5#nkZpq5(}ANIVk*7HKX=fy(Li}~=2Ip2#L zfuA;=Z32M?=oUib`VNn!U4q$)Ei37kXsr5bnsh^>DjKOElY*wJ7vko0p`F0;!Kyhn zMmlRU`5BN&wt#a4|JR^-Ci{YUNZVJ;U;!khOpHF|)%xK~_N1ZTmc(PSoRKTnOs%gl z^3fQkx7pWllOq2UtDq2z$EZy>lJjk2i>JD%0X0ybM1q#jxB!vbaxNiaKL(ygOOS51 z097ui(P#MAu32Z+WICbfb&`?(6O=Cd#9Y8(GV7Xkz&XHVbdB0{M;(X#Fd>YIpToW% zCFh1~BzY0q=*DTrHi1KfH9+UwC_*xtKpdN45i)moTqcVFtFJM7WDQqf4uRPm>A*hC zG}KFG5e6&9p#eLN*$QDq2AaZ*fUU4Lhm%Dkuhd0(%{B9g&WjP+==OW+dr&x?#P9)d z<_stq-~|-c=DM*VYJ)DlopJ%g+^stU=xZVl2(QO)5yXNi%HAqNWz?hA#2|}iQrAs; ze+A#7)|&;&-7sUV!OWb+zR4p9;7XFcsXDQO70iqpwu7uPz4ciTt-y_pQ;6yVnj5%q z=Ti3W&6S4xTOYW7R{aZCzWVh-_3QJ_M{WHpiPilN+VX8j3vEZ=56?U2M~mUQhv98& z;cd%Z%hUPr-a>e9&bL>`1+wbdj2B-;PF9bzV^XlH1z{|bu3>XEdn6;YpdyLP<#ck| z!?R7%dFs7 zS(wXlXuyp@H#}>mSIgE^GDYNhqX_zGX@_^_Sq0t*sq9!cx3}Cc4jRx5n5nI;Y}k!4 zCWuP$#Ka~|l%c@3IYehk-g!cN%lG(?xXUooU2LA^-*+q{W#d(8p!=?4p#?@dsvhO# zi*$3Uj)CW7f-j91qs%rq5b*15BAdeE5)X^ zhfO=yns%)0Uv0}b9V#>(nhzF@Szyc$f(Y`}M+?P1I<`8vWcqhbHwAQE;@L$wcAFOXo_rmnI{q3Z#FP(g-E$1Q}D0wudHHC z<}80DM}Q2N6tr-`(87+zk%iqkS1W$-+9^4l$Ov#v&38tZop)k6S2uonS9i(bK!z{i zj;>d=ka05#<0ed)JxldV@w?JeTcNI-ES*tUIvbkF#u-I3&241ijG7kCD0OTNS~yR2 z$>DbISlUVJ;i z*ZqNorp4-lzq8~EOpVqJDwV7n@L-kz`uDB@uus^ zdkBblSGq4r?op2z5ZzFgc}1t>8+R}w?0GK)cO<72xMH|JafpXlTL>gyS&c_^%1==0 zdC?Xr6RTN!F42$Y@H}^uAFTm#4yqxj-X?~0?q#}-5fOtwA|egKC{U3B)kUUX=6f-` zf$Fg%DFsOV2+CEFOL4RO48QqNa~U4&KSpj@*>T@#=R;>5S+6lSjw`D*pvG{NmA1=- zi5o8au~*TqbH@3nCuf|?me$J+*lX(Cvl~vS?yIbj5@K<7?8%WCw~;P)WKH!d$7PBB z>zC-UABOg)?_ixqn9Ipi>wE1r>`xHFe8bF(5o9@yE~g#+iRlJS|9<&6hp04|&z6;{c=!F6Oh6k13KRvWz-ywT}?3JC2Oh7Pnf{FltQHh*q z;jy)UVE@4M%R}VlL*7Fo1PI8u1UE+UUD~N`1+B_12BHBq0ErI7lzhZgr#zKbU2mLx zz}J@UMadbG1iX2mi2$*HXB zhAJj8LANUz8MkCQBP#?+bU+!tFV(Tcgp{}%)3u+|?N%HauxAd?kyStg@P9FsfKUal z*S3Gu@eezSp}jfwdocL3Z%iVCkizu=H2VTnp|*8v0eBlhrWO4AH8(0OUd~kdI_L8)$ zd_T36TA5l^{`&UH?MF?KM-7c72j9B?vD4Yu^f`y%vD4jL_c@0EWU{sn!|2?JDk%Qj z8m_+cQB7^G?p(g+e4*z2W2d9O8l$VPE^&^kYDULw$WGv|Av+?(;>>(4{*&jd9_Myc z+nkfMmoYq-oboLCg@5f7j$5YnFx7`K%}W<9Lo`O6L(&u@^|t-f)Ktf4-=Zi9R-@<( zJ@mD&`Pxkv)JNfl_irrRAZMn0xU&%M%=tPuE(Xzawis)O*k$^xg*`4)I*~8aW;-^| z@>ZJnl-d@`UQydI!;6sT|IAWi*6C-i`{f>IUFo_mE=vk&{p#jqdXLC8>w1SvyKZnd zo$qircxVP(;|{pOxrfz2*(R&UnO_idrIuetGoQL;I*3$9Mp3;`1(9>P>V(Xu22Q3$ z=_bQR6e2G()stYZ6snuuWs_^H5MmjpG|k9|aWV~T!segE7CyO&cIUW9wc9?9+}p8o zp%59&*B&g?9-Q|)s;U3pD|b#U%@i7Tb&MA8>ud;zAZreSe3#~|WK9XkJcz;~pc z`+0rnNW}T`Z9GE8t=oiO0ulx&-G~5Z_$#<;7xeOU7-A~MGt<&LhQH)@0k)}v=7M+u zF{_Bl_{ZrE8)$EkV$Ktkx1lD0ysqgEl-)b{kbPP?vq8E!nzL`TRQ)0fX z@x9lm5(RxU>VJU-Or8r& zT@aS&5HX4HQui>X&kF|6rv^tY{GFz;w;sa8-=V~S>V&_N=2>gPB8Ew0{{NW7$=|{J zK%%-0`AI9lmhdQv@LXk1nml9Q7IDNp&}H#L&Lm{ zh(Q-HTvu1l)dfz8D8n|Q48J3SpW!tOKf`M%eugI;e|o5)H;v~10rU2Jg>kS4(gT$v(91$b2QyjU~&TQD} z4VV#ZkCizgYV+(Gj9mdeT0~!8@_q=Tj0Sb%@tKT^Z7Da9qd%pEB!UV24u%(?4dVTW zp!&O$%+(*nZ@K&44lTCo`l(-w+xiYUi#EtqlA==R}+~(kL}PR zY@`1tyATiv&EZYpGGIWx!&!xt8U7H;iS**NBYq8&KPz2^$`k5=xG>0^vCkNJ`>Y=qQlxq$AJ#_W}B6znZKTM6QzU{Em41PXb#X%o=fr8(#x zUNCpa#?qjY-aK1^0pY0T`N6!>tSzzyWOh<&X$)_V8866b-3)_$@5lPfKSqG~Us0SA ztnz}|052|!JxYJ6^EKp?_c%?mXi_4Kgx<8(sTq7= z$pM4q>V2@G(z~MCX9{$W40tb)vl`QZ8gG{#AC`ZJi8EFTR)atiZ|^GEcse1;w4<6s zsE4(usO~iNq_Vf@&DDr$dN(3xm1fHtkmog%?gOPTiRAA1DT^9|pVDf_Mx5 z-l=?WcOkg@Z~mn4jkCGn*^(3a&<9o3Exfk0?SnIDiE#5P_y^p1cMcR&deeFN$K?b)DSZ zoYT(_k=~lU3IK4_-n~eHs47A#c~y6U%i=2sgoeUi1 zF7{f?Le6Q_Li--0wnl)Tn+b4WyOfHm>?)i7YLWD1S!936NA5rlr7w!{`9h6B98|gXDmwL!9cy zhY%!qLDAG`7eF9zX*8m-f=1{-`ma&!mjtB$7!gp2kVYZi$_Kj(L6W=-3gHdCH_INE z+;@YP^tz_G*M8m9`LS=M;YZc?s`E{|3r#R(yU7@g;Qhe7dtNC9YZmvse*iS)_F6EK z3r32e+WBL@4z@21E!XFR+Y7<%Xwu(NY}-2j+867=rX>-Da>19EZ?8%}y^`yFIp=zr zkq6sb?gSwO%}@RZW&1g%;4)dN${}K0#$#V(l7tB*E9;syoX<51ZLkV z^2~bCJHAFVgD-B(c$ckJ%=nCl3>G4P-&Nrv`4zKDe+%<^<^SY}L^np|`2?`}nMoz^ zq&4_J!cL4=!{KX19$u9^&e!^?657!|ll8m5 zCG!VSy>n_UIICnT3FZnfoZ?NG^ks-zDzQ08l79{mJPzg2zrkIt!3;AuV)%TD9M?YY z)vTq!6b9l3b0r8I%V71Qel=wM^b>s?h`!W=xsvJJC`y!1_3EsiMokHSKtw0-febZV zb|_`c;KpwfG1AG1=r2%DW7C|8Yoh9fp*;pCQv3IaG(*gJDoVkBB~nSC2Enk2+a8@e zk*gB&u5HCY+k96c(6)47S^P=z$H^aEy>~SicnQDNZ)x|rA#hHG;MQg5JzqZ9hi?Pn z6A7H)t}E6x-q|_t{dKT$@$wI6^1)q&;I0z4)n8YvZ@Y82#I;qu%oiikhmiwokpmC9 z9%S>8qlL)P?}is$i;1QE>-9~G2aD|;i>KC`S|2v`tTpv4XIIX_8R*UPxu%|c(_4k6 zw-%kn=C(p}bY|HGccYd!Q*$o_oKi9*kb@19vay41Cl zU2kq%yj|>!ECnF;KI|A+>li4uY@uIgq!{flKKFca$3Ury>)idA^LE0tj$rZCQVqAI z>+Ye&qou7}b35y!Byi0gG=^_3H5XcU=bFE{+WXU8xUqqRYD-6WE*NI3Q980-1@_ewp%tb4`{KCE@t zV>^Lxj?H-N?(eb(=K^|3fFB#-7TQ?77SyXMw-3(DQ?XL^TCLU*Qfr{SuJ{Bde;m9A zqng^+eKc2gjR~`=i7a%LlvLUm+!*mK%P%^&CY)v8`D2ah&5>_CwXmVAU2FAw35skG z#4k|?MBJV!DE>ioROcScv-llc=fC6+GdBY`H}yxoj5m}?5u$qHllW4aC=*#z1LPgR zBuzyo7LQ4SC|>3snOdLe$QmjCuPGpoQX!oJEdwr%_`OA06tqARQ#!HNAbuU3uWoT< z&D)amwiFwi=_@@&e`qm~^S9ymtIpl4&ehR;=gWo8m+@Te=zG|)cdcXZ>b`u(Hwqo! zzz5Lax*A_>gQv-d!4HCqNAtc`?VUlmR{BDV`|({h{C>4%*UHH1j{KIxg)N8Kr`GBg zZZDn6g?nsywfE$_~S^dEUMY=?ViW!1>?z7=;qI8X=M56f9BjBML|@&3p=&^^oc2naWLdox@kB)7#(1GKMXot#|CKyld{xokP;%nFUL9T-UmRK5c6a;YXrWptxseDR zNlkspOEDi;-&FEb48Ye|3Q{ZtJxi&IVw^oV%}031WE+FWl=gW!<22t<Q zuDM|8G~dFWU%1Tkkjpj?AG7q&t-0r%13c_18-vBek16%@a@Hljo+k_O=HX)hW0v!| zHGfwVHNG*R#*zAYIcq;x)mjX-6oXB8Rq}uXmYxHS99O%z=gtdYRQ~wx_2p}Y&i%Qz z{e}AHk;zjD-tm~lYPbW3OU^J4muLh<=IvZn@OQAZVo&eAE35VQGVE#H?Jv2FlB~EE zbbI+e`f3$!_-a*PbE6}U6Nx97dL=igj-d-2`nXs&T*p=#GkB3HGi;NDwuqgIJ~ JO28<`{{}7K;zs}g literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/click/__pycache__/termui.cpython-311.pyc b/.venv/Lib/site-packages/click/__pycache__/termui.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8730d2d06ba1d1f3525fe764b7178350f3322977 GIT binary patch literal 34685 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 YQnk{13mNd`&Io^esPe~#0dtQ38^5%$0RR91 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/click/__pycache__/testing.cpython-311.pyc b/.venv/Lib/site-packages/click/__pycache__/testing.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6c0204701d5737ef0af80677fce85df6d5f8b446 GIT binary patch literal 25749 zcmeHweQ;aXmEU^+9teN{0TTQcDT34&NlBDteVUSK>(i!eOGzZhF{6Zp_#P!lAV9wd z>VpAOX6rVzm)_7RQ!`n5gUl*kW~_A79q-iBXz1({!fKQt6#elPqrLp97_l?;zZh9W#C`7YNQ&62&y?Mv2;M~9+3=i;8? zME}d27`6Gnqu{BHp|iNgkg}z$Z**5=jM~=Qp3s)8)Zv=3;AO%F^qB}EQLvS z6)7S}QHK;>q^^ZODtdtAs1`gidMOPYp3R7flqMun6O$Ruo1V-tSC%r9a_aP`Nh+wH zNS5C3KLYRum*unEFns!xb>WRhh&>|3nItZ9sL^%$WRF|(4(kFC;F+&!;D()YopG{miuOu?k&IyoE{Gz0sA5A7kuk6Z53QI07Y?OY6TM0MLXBNJeJ5mU5Rl{5JzO6DXHkwPm>S#T+oVEUGcreu5 zWw`pIwA$OBv-jCZ0@8R3J$&2jC6AD^oJ^G4N zs&jUX!rCe6HUJDuI69XtalC(1F&LS9_HJ3Mjlr#ZN*pU>WBCkCwE(?ZEcRrAo&^rQ0Fb|To`d3h58rfMBsr}Px8 zYzAOG|JKy2Q;VCIw%={-z0=yeyt~l4Q*GT@2=}SszPzuGb^G_Fy8<u$AmcOm?!8h$kIdsOeQIl+*Xh?o)bX?VT~Ql90;c#(hE_lj-u=Il9; zPJiBlW3dj$Ip;fDyGQLAY0l7sbiW_qJNz5mMa-M8G)?obxN-K?l z-#GQ{Q;RRX{@lWIdYB!ShfwoSxojZi-Bge@c5JU_l~znZqb<8AJxx%I-%2=YFMWCM ztwVS(L=UKd;R9;;K;Cy?_25zG+2HlU;~YBs4pKQp`p)R09buxf@#U=^j0#1r!KmoL zk5c1lXJu`lKfdrxAskb~vAi#)qlTAbi0!E-G^FC=((ter7#ez9cBFU;2D{CAkD30WX*jfbweg@NE0sH02jq(ujWpqGHkn&X~~uegPP}A%tJO? zG~XbQ9tUG4@2BX;2+%BH&C+L8HN6rbE=3_Wa>o2Cx!gkgVtnaxiG$~M=R3X3^Iko3 zDnWo3wk@6oJ0NV!eg5Y2%u@-x9-(egC~e3D-SBGtjg&ZXYm^J?pM zia%HhkfKwssgt7C1Ul{sm5YSg~azz0cxLpOnaJK1^|dxBD{yw4$yn;R%qF1knRo&THfrA>WM! z*t%Qwa&V|h@`-{ZK$h~Y61n|m9Hc$x9y){)uJc3HKt%xZ>1oVA@tkx$GkE3&IX*EV z$(r}Vt zp|#l9v~aoPCSUh<-QBZacaI+X%Pq`z&mSrYNKxX}12vqtrsU##^)p0Q0|ORJRSoZ`QeF_?B`UEjdJvs{KId-)Mv&QyN@UCWGHbWd}s-b~0yMQVl& zt?A{*S&!TRLDy%*+1*N3eVWS<4_tmO8*Ax$y(CI3KM(I4RzlBdUC8Y_mYz(Cu~a$} zBgI`zSKP&j4VUB?w0$wAGm7aOl`how1huM5afPW!s2_~jHP2{V$!M;@Gn$_?h9_h> zEo*^Uw;x8je^pLlam z!QY|!JBW<879$OB1iu|ze4!B8qDHpN3LjL5=K8-AUl@Dy`P_*@W3SrSTd3ZyR&URH zw(IK=nrA-7c;0Vjv~BH%LvBAO){@E_dz=S)O~Kj+C6A?d6sr(pYCECj^of2)TAPki z3^-y0i-HhtQng)YDfy+~+REm!8nK#mq*4u3&SC7qtJU5SGp=UU9$ah2L2K&VBB3GG zOC)V+RK$$ysnfh)kd(<}W@^vV>7=N{GMA*-XnX>CQAq@GQdBHG7K^7qo>$XX5P0m_ z!I&~CCnhp|r!}uUnSusD^B+qlzMy-9N=Ag*bC~hY8ogm#HQscM>+scha#GU#(sd{$ z8I{62Dotb(>6GS!7xXul9<@(h+QHdUbqSt_t7X|9Z|(RV`;MO#@MbPjSuftqg)Ccz zH(CT5CFl80y{!wG%BS1}c|N>7E#-O>yAXVfWLeHh0R zsh|5=-q)(nU22i>&;YT)&cNejWODX&MtV}+nged_MwL5Q&K!6%BRrx@bUXJATD7OP z5(W$etlxhP)G?970nR6`P~a0j&?7KH(Y&HWXwpfCEwwW0T7{zt1e!R~@%So&6p|my zID&Y4H@xjmc-yk)R<+uF=-n3!;iuH_Q+LB>?u5@2gLU)AKXkhyfsZ(V66f--!5Nwe z&7oW;LTAGEZGEk6mndC-*3pA=7Rs$nzY?iAbDkNckxPs4D&%{owm6WF^#j}EYT7$J zwNYPP*siKb6LCo3Qu2nmfXNK!3hI%GlEBH+tkMEsq~(Y0oAM+@vRS+CATa_*8|>qR z*VmC#p>2_kQ!t`dx8kqBiykGK^=0ApImPrKTHIq z&>trQm4cddnipMm#tqC1rjvDoVU6P-<4icq1A5*RFdc-`nkRiFe&ZAV@F#ri6Mmq_ zqpy7jQI+P&fDK`MdHIk-tD-d=D}+M@PBd*>=5&qD_YkNM=MHURZ{MxHeBJTyY{u!$ z*9&!9)w-?ux~=by%~ln|d%m-G(erx$Lcbc_nh)>6Z@Ec#3HtWv>m2RgJ@pkLf>t#= zET%`HS~`Mgorm(BVVg}nsS6B85ut_X==6lS4+-ZcCz23SiN}%&`An>kzeqkNYS8*7 z(*%~U6QJ%@s(eHWBR~|U90Iau%)g@N@x15pQZpB-Ej4T)4FkYHf}5VDIh=rQmLB!L9V{36e3>@SKqMEzc{W&ca*{u5aFWr3%$i)Xzr=` zBMT=NA6M&pmLGq2XTJU^HTd*LZdWu=s-=WfuMPAwnZqS)Saf4G5jI%B6iq19$C7!3 z040NC0W%qe23az%o(v9gi#jlqQ9#5c>?L&$oOOXd#DvXJ{4<~0vhV(%W034>4`TH6 zKd}{T9*(Okm^72QlRS3qQTiRQ;0&#sMQgp*K0GWze8Ns zfw89E8RN*oUuV=VMK6=Kls%3X+rq7JS$nj`d}8!vp@J1|FlYng)Xv7P-ci1A*^Uvx zX07tuspIztw++B8;kOZev#e?YQuA0uYyxexIB5eE+x!qLv|4sEYh$`%9POC$h%Kwe zpiOjRZ`ml1VR+*YFnej&C-FiTDq>LJTuq3Q5*wRLjgo8-PbM-qVwrSV7Kz1U5IaV% z#Bgjz_AW6xCJPX6t;;7&ss_KBDVsvXCMM;Hw1NT?DdbHk=_L3CF$OD&gq%)|OQ}p> zEOzcvLW!kQ$s4SsYiaokOAqn-Vp7_fxx^%PF{a#5GSavbyOzjY0&@!q34BL7H99HF zki2gYyOPMnpmj;XB!k2%R@}v8`a(R3`f*w?0bvNDKX}ZH)E8jU{lvnIQ!dig^y|_X zUgD!Hr3BppI3W~<5@5lCN=1V;72}zBpS=+Dsvo@+6FTbT8?34J&c?3BVMlTyNf<`4 z>8s#s60noG=qv}82-wRJ-XBYhp>m)HKeUfVV&t4WDUIx)Hl>&{1KDF^a(W#7LY5e_ zeNb4t457#7q5z%gHSmstVJ9;-nPe?eE~T$gdD8XxIQC*1hxJNQ(&G?Z6Y}WfxUL0J zP~_=!MncQt8MN%;WHK%jNsUir)@{$VL^2tR!@dTlR|%Z8f|r!geGB6b%#0_l6Jmh1 zH8FD%XSF73^lq{N)3e0lvQ824b8F(xKBkV#?&` zCA}yq4&QkEM(lzV8<*k=sSnmG!`7klB>MzbZDTtRo<4bwX{9tbXjcmm=5@l;0v4+E zBOJRhVX6j*i(9Q4n4rS|o7L9C)B~o_5B`?P1K&iE@+^T@03h6vT4}8)g<8bM&nDB? znOYH3tp9T)W5=(M8fv)a4l=JQMjPiJTOBb zxk$?p>Hf_@WEx6+eUxHGN)R9|MkADRBu0A5#Dz)BIjkllBVBSjo#`4Gp;ZHFPqQSf z9QrgObm24@si29clNG~8>JQTGsBO|Z26(jWQ3%G=U@RYu6-~1< z{ggo%O()Z`;}DOS)=l_#|Gz--_06VlHtUD1c6$%9v9zHT^Vu>Sp7ua&6&&XZG&Jm) z_Bz5nW_Xn&+*~WBeHqd{l^=_pp7uj5w#5vajP|%1Lj z))DEe&5kx#iQZS5hfP-9Q3v&oRwVX_Ridx54o3}U%^2Tm=+&*hlm%h}ckBMemC;H2toeYSzl*|Uu^9e!@@lClktb8`nbahc;* zIh#4z&2ukubH}f7*WE92*ZAx@?a<4g`%*TLtsZmfW;faTPua(PMjwA``x@72U)QH> z-~Oy)SFs%;`PN=5vX0%!T2ZqOdb3f9gWiTMDydtCN}_91N!GviUPk=jChi|G`@6@i zK|wuD@f4VoBcun&!0rhGQ3@9_NMMJw1-2K$?F3_(b=3nj8cfVJnL9dYHQ8i?Univo zB<*z4kot^*Acc{D4gCWv^CIK(b-e&71I&U*NidRD`pVqph?T`;e|3qSSb4n^OKD(n z>P+HgFBTvJ!J(5 zi3Emd>y*RAG|+%5sFD5SQsz?sh<+kH0)Z1M7|~WjS&hPQp({~zwCLh9sVzu(f|f)5 za6{>1h_pId&JA?wdDrI3A(^j*B}0Qld~kp4+9foN5ddT&cIhYvod(%~5Q)Um9mX&N zLe15Oo?BQVOjr+uc4)ewlmN+$;xHapd!VT>#t%q=BnAs)q)B9wH*Bcr>x)6HqadHI ziW2+#V+Z>lF^Pk!7#Yz8dJ@&3`hv0nzKqWftIOx>XVV#l43>l|f} z@d->>$X0+x$Pf@A1=2zBD9M4prB!%(` zb(oFffX2&^jC{=a1@e+*`y~^@Ipw2d7zw1iroW(r16riAdyxMZk>1JS6TB-qav9-+b9cddN3Men3h6gj; z2f^^%sk_0pJHfWaFD{<}LYN2kw zTDO1p*ou`g=UyD5ze2EE4R+^)-L|+waHAUBm=A7*&S&-%(?X1zk_eh$648Ic%Rh{W zFmSFkp9gbOT4(HkfR%!NFF`up6pME~OPP2uzJcO{KCZ>d0JXQ=R2Jz3(WmqrL;RYlV z&bZ&{qwAd%I<@7YBWNVsM5FgC3cz%YHZDB&#=y4+a-D_fW;MEb_Bbq*p{xpRTZu#$ z0(T>^JCRtfz7W}}Mz-c7TW#~(HWiy@pV1GOPoPwJ0l=XTqzTH#tR5bklv#ep{fa9H zoBu3NP`@3t9kE!e%rdl)p|ND!mvgzQ)%gH2l1NMp$5TpTs_&t_UzL6rp@C#Z5HZXJ zA`P?C#SPv0rtW;C8~1kSAIk^Z^j?u5iu+Ngdp5}z;MLXFY{vbFUfHy}PCgoTEqLu4t~b z0#g(H^iFewiZs7zztPj8t3pYy$8@A@T(xRumZ+~7rvhC#RxoP~v|?3CbMy zrw8R5Yaj3Dn!1;T<;<;Yq4BWVczCv&ZYKmjsBc;rob|6XG%pOz1`KDz7Ig!zbT${e zHoq27eI55|>b^Dp>iFWZLQPDqiOsq{XlhxQdOf?4oekcr4$nP-J5T@zDZJBpDF#g_J^wqip^ zv7x!x)KjYVw$^;e0enP&@_ZcO0uA#+1%FKS$8fE{--N3I{-z&x-t7JH*_*hPg_ob; zf|n6d;e+W+pwr0tagC!aw;y+<0AP*X`r~6aVM~pdpB!V(TEHp`={^oP%Bu1=zX^LB zI6p)Ia4cYDqu@FYSCc|O=hOVNJgz|aVHFOr0+XauZ@#pYQR_Fe(3QRW-Z}M?jJo$Y zd;I{WPlAz{<){GY+om41>u}!JvC_Fs?d;F{HmPHHHg{?ZqvRzUEbZ zUB%6hklR^o?Rw3NGqkQfuL(qHb@j7VCD#W3f#Sx_?pkdpN?;Kq?wWz#)X8ueu+L7CkuiKdqmVfs)Zu$QB_r|}Q zUP=R>)C>T<8NZYIS~d}h70XU@C*B5&Jx{)NQVnh`b`OxdrMPj|YbWQ<6t^CF?SvZK zRNT7%HB5s|dG>oy>fk!I{{FUce?D0LDHpLS{dL#lXE^RxvCuPpu3zos$=?@v=8*8K zgD&#-^W;C&0{`DU5_)#P^)~~7=c9Q*voku^g2DP=rIy}i%NOIFID3Ytz zVc9)SmVG*u+5+V%ZKUM~%3a*5K#y#78F5e*SIDu`p%=N7$54{_ITsyN<1kQvL?P>f z>?>qLqIb!at)g3d(}8(DRf{^!Lm`esoyF;z4B5(;AL}U1DTv^h&s4obL2uf=ISvs_ z>n=xV*eE*_Gkmz}WIvuTkG|HnfXdcb2U*UMnGR>eGcYwLS9D)tyteGh)=XDB#x`uP z*;#_}T!t9X@^hIuQugF*p+=bVf>t){98u>RqySq9zpY%csxr6eqdrXsUnDxO`Fc%i zukK#s?FU>Kzs=J%SwZ3dfTLa`SMbw~rdh7fDA%B+b=qyao@L>~Nh6?Me6+|Slbm_% zWaX&TvrI>DY-rMg>_%&9Q(2Vb`;6t(rsAOOwQ>IcvhA(^khUAR7oo4JykNm|sp?JK zZcg!BbLodZbOglXFSEzOYnIDKvb8ww31+LazFYpcu!_8Gt|U+p1mYT&%|UkGNQqgN zD^QoxJ*4%__9U28U7RE44P#O!iU}E}FEHwY;+GVQ4i&p@GsrC2Vk2xx zABlmNh5?{u$>gX2+DHZ8bTSGnE2Y0aN+yXDS1#hhAG1pA8;72E#8h`fLux8cZEdhA zN16UxH_M^k_p=+u{UiECnvs}pzhg^psGO6DvcX{48WNqi08spR#doC@LZW)?$oHxWRlOjj%ev%^lN0duR>3W|6op=VSXCp-!1*?t* z=){B_#*COJ0;_X9{77I`C6$~)KVb%Ajsu}IwD@2nfY=+cGz+pA3XoL=o*c9hAM5$UQznBwC9mt%}`n9(qtWH%Od z8#mmYEgvB0(@DQ~h;szXQjLx|Ow8x(&$R(Bo$$4v`AN_30Qm5DfuWx zJxKu`c9+l6PrpksKcE;Nv`)IR!b6Ai32+UK z;g@)>zIoPH4Ap+?tFL}Fw`KY4yTa^O3!wouG*IGp`1ilpTinnw`)qN~f!V=ga|>>7 zhg%jm|Il3sZ&t%30Ec>3n%eN0y}gB|Zndd<-c$0pLx+oPo!=k)-eB%Zq3uz%?a_Jv zy#K*U6t{@@&|wP{+hTXy_TOpSe_JWE9a7s4QM!3QMCj0ACPH_F_7^+0Eh17@z{-Y=ONYNZurx65TWM)sYWyL8Gw|cx zw+{Tpo}cjlPPpB#ZXZx%PrO(AmyLy%r`49H=e_r$E%O7#_Kou=;amLtw-3!9D#kkJ z2R~@)%x(Sgrb1Jn+SCW-No~gplv}6n)^EO3zxjt}mm7cZ<(pqF)bCd7cjxPO+v0NP z3iZ8eeQ&Nx5V-sfHLzwhSB?{SmgS9i3{^?s}C>459~w!q0=;r*@0YEC>R{Cux~pr1b$ zLeMX~ttYn#zlc%DFSZC2((5Mw&Liz8(o%8g`hLxnQqi#O4X3pNq52?lne~Kjeq)sZxF*~+9^3f zs`QYIK{2LeqNg(Rp-kF1*i)$oVJ+DD>05AZb^UIt|C(95(TW~-{O{0&b&P>VvE1WU z64+d#fwYWo_?D%UG<^087`oYp&d2DNi(t5qOG#u5uFEr&gV=W%=a)@q*u5rX!53hy zt1iq4DUQ!C!T6t;8D^wJvQpV(UiWSnt6=GM;Gc6_~wYG&3U?9vD0 zURO&a25I-ljB59An(3G`WI5_PY*ui+0PNa0 z>|vY|1?+E9u!~8s58*zXTdOpRv74V5opEwj#@35ZAh^-o(>>MlUx3IoFCAxI6ZPpm zmcSk2s_`o#m7xivmypuNZZO`(t6ZY5I^$y+<6r}j{LER#x4;O6lsxi(rc&Khq)W^w zM9WmQzSl<$aTuS2#tkVZ5lpq)HvY1-Y>R#$WU2fwl%juk?Bf_0uANJ~a%Jwyta~NY zpoZFW-TBb=LTI}h+CJ-A@df65^L4KT={vwBkKf<2QWss=`etGFtV0E}pscEG+co|3P8f36Khk z5f{6d$p9S|D<3e%aR$sI{gqr1!B^r4bmJaV@z4{+4KZ+xrRsoy?+pUntF12y^y1}e z!gE85{E|PnDfiONsoR@w{*!#yezp048ai02q9i`9p{3*}Ux0k9j35`NDTOGEO0$7x zLFihh6DFbSU3_y8P9=zx52C7sI-ITubw%)jt+^vN2bV{0?|!HM-O+cR$oCypHy=}5 zKyOHJ&mWj;ncssp26B6r!ujYn)!$tbjQp$+9n^8&h$?JErw$&bPB(5S`JZ(O2TB~l zd*R636uw-z4LzM)j^7gVU5~1*d(`mWlE6~^7F@72J}y#UE)?f+)pM=5zyH+Y(WO(% z{H?(4N8jmJy9e@Z18V&fs{hGSwN<;`2D(_^K}~eAmE}DzqynH))GoA0;r?%`@YYvpESQ<2}cD?TTS&G0zhq{`j z338y45cAehPxaWwYKQ|KQJ!M!Ijc5MPy5CBLh7`ojz z4=nGw?Ruv=zx|N9>9E@TI7>mJ+d6-2uA?Lv=~*TVQ;uML28@B`VKMO=nhhfaXu`;J z3@-mS0yHP&{|bPw^WR`om}a#m(8n+o{euzA%!#-%X6?Z27w|C(Xb&dh8JSK%@bUi_ zKX(FF6DN*6GkE$bk~3wA-Sg9}D*h+srFBAP^ZO}13sgJiCl&Qiys^cA_7dBQz-%)v zP?$)7x>GT~Kk*&bzl=H{-$yKue~KTI9BU=d7rENJ@hfuv8TM!M1ZUV^kqgbRzakfy zVShy~Jj4EqTwUJy6}gVQ^LLMH&O3iau0HSl6}f2M`73hWdFSt*+w(Gn8lLYedOGvY zU&-6SW}1wcEl z4MvtyT@5mGtHENI+S>aeMSNt%cGdDbiq*ln{`vUA#l_LwzU9taoAVp{)W%(E^&=%W zMIRbq?mfZ#@=!@YNQrZT?gKoI=2wFcDeNOFBEvr^@R%cO!w*^bN9)A0iST~_SWQ5Y literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/click/__pycache__/types.cpython-311.pyc b/.venv/Lib/site-packages/click/__pycache__/types.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..07ad8d70d1ea36aeb9c1ee91feec5f4adfb0cd83 GIT binary patch literal 52838 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�yw1cwScjnr6UU$wPxb`?aB|q6={|2!! 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 F{2%Ao!6N_w literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/click/_compat.py b/.venv/Lib/site-packages/click/_compat.py new file mode 100644 index 000000000..766d286be --- /dev/null +++ b/.venv/Lib/site-packages/click/_compat.py @@ -0,0 +1,626 @@ +import codecs +import io +import os +import re +import sys +import typing as t +from weakref import WeakKeyDictionary + +CYGWIN = sys.platform.startswith("cygwin") +MSYS2 = sys.platform.startswith("win") and ("GCC" in sys.version) +# Determine local App Engine environment, per Google's own suggestion +APP_ENGINE = "APPENGINE_RUNTIME" in os.environ and "Development/" in os.environ.get( + "SERVER_SOFTWARE", "" +) +WIN = sys.platform.startswith("win") and not APP_ENGINE and not MSYS2 +auto_wrap_for_ansi: t.Optional[t.Callable[[t.TextIO], t.TextIO]] = None +_ansi_re = re.compile(r"\033\[[;?0-9]*[a-zA-Z]") + + +def get_filesystem_encoding() -> str: + return sys.getfilesystemencoding() or sys.getdefaultencoding() + + +def _make_text_stream( + stream: t.BinaryIO, + encoding: t.Optional[str], + errors: t.Optional[str], + force_readable: bool = False, + force_writable: bool = False, +) -> t.TextIO: + if encoding is None: + encoding = get_best_encoding(stream) + if errors is None: + errors = "replace" + return _NonClosingTextIOWrapper( + stream, + encoding, + errors, + line_buffering=True, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def is_ascii_encoding(encoding: str) -> bool: + """Checks if a given encoding is ascii.""" + try: + return codecs.lookup(encoding).name == "ascii" + except LookupError: + return False + + +def get_best_encoding(stream: t.IO) -> str: + """Returns the default stream encoding if not found.""" + rv = getattr(stream, "encoding", None) or sys.getdefaultencoding() + if is_ascii_encoding(rv): + return "utf-8" + return rv + + +class _NonClosingTextIOWrapper(io.TextIOWrapper): + def __init__( + self, + stream: t.BinaryIO, + encoding: t.Optional[str], + errors: t.Optional[str], + force_readable: bool = False, + force_writable: bool = False, + **extra: t.Any, + ) -> None: + self._stream = stream = t.cast( + t.BinaryIO, _FixupStream(stream, force_readable, force_writable) + ) + super().__init__(stream, encoding, errors, **extra) + + def __del__(self) -> None: + try: + self.detach() + except Exception: + pass + + def isatty(self) -> bool: + # https://bitbucket.org/pypy/pypy/issue/1803 + return self._stream.isatty() + + +class _FixupStream: + """The new io interface needs more from streams than streams + traditionally implement. As such, this fix-up code is necessary in + some circumstances. + + The forcing of readable and writable flags are there because some tools + put badly patched objects on sys (one such offender are certain version + of jupyter notebook). + """ + + def __init__( + self, + stream: t.BinaryIO, + force_readable: bool = False, + force_writable: bool = False, + ): + self._stream = stream + self._force_readable = force_readable + self._force_writable = force_writable + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._stream, name) + + def read1(self, size: int) -> bytes: + f = getattr(self._stream, "read1", None) + + if f is not None: + return t.cast(bytes, f(size)) + + return self._stream.read(size) + + def readable(self) -> bool: + if self._force_readable: + return True + x = getattr(self._stream, "readable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.read(0) + except Exception: + return False + return True + + def writable(self) -> bool: + if self._force_writable: + return True + x = getattr(self._stream, "writable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.write("") # type: ignore + except Exception: + try: + self._stream.write(b"") + except Exception: + return False + return True + + def seekable(self) -> bool: + x = getattr(self._stream, "seekable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.seek(self._stream.tell()) + except Exception: + return False + return True + + +def _is_binary_reader(stream: t.IO, default: bool = False) -> bool: + try: + return isinstance(stream.read(0), bytes) + except Exception: + return default + # This happens in some cases where the stream was already + # closed. In this case, we assume the default. + + +def _is_binary_writer(stream: t.IO, default: bool = False) -> bool: + try: + stream.write(b"") + except Exception: + try: + stream.write("") + return False + except Exception: + pass + return default + return True + + +def _find_binary_reader(stream: t.IO) -> t.Optional[t.BinaryIO]: + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_reader(stream, False): + return t.cast(t.BinaryIO, stream) + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_reader(buf, True): + return t.cast(t.BinaryIO, buf) + + return None + + +def _find_binary_writer(stream: t.IO) -> t.Optional[t.BinaryIO]: + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_writer(stream, False): + return t.cast(t.BinaryIO, stream) + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_writer(buf, True): + return t.cast(t.BinaryIO, buf) + + return None + + +def _stream_is_misconfigured(stream: t.TextIO) -> bool: + """A stream is misconfigured if its encoding is ASCII.""" + # If the stream does not have an encoding set, we assume it's set + # to ASCII. This appears to happen in certain unittest + # environments. It's not quite clear what the correct behavior is + # but this at least will force Click to recover somehow. + return is_ascii_encoding(getattr(stream, "encoding", None) or "ascii") + + +def _is_compat_stream_attr(stream: t.TextIO, attr: str, value: t.Optional[str]) -> bool: + """A stream attribute is compatible if it is equal to the + desired value or the desired value is unset and the attribute + has a value. + """ + stream_value = getattr(stream, attr, None) + return stream_value == value or (value is None and stream_value is not None) + + +def _is_compatible_text_stream( + stream: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str] +) -> bool: + """Check if a stream's encoding and errors attributes are + compatible with the desired values. + """ + return _is_compat_stream_attr( + stream, "encoding", encoding + ) and _is_compat_stream_attr(stream, "errors", errors) + + +def _force_correct_text_stream( + text_stream: t.IO, + encoding: t.Optional[str], + errors: t.Optional[str], + is_binary: t.Callable[[t.IO, bool], bool], + find_binary: t.Callable[[t.IO], t.Optional[t.BinaryIO]], + force_readable: bool = False, + force_writable: bool = False, +) -> t.TextIO: + if is_binary(text_stream, False): + binary_reader = t.cast(t.BinaryIO, text_stream) + else: + text_stream = t.cast(t.TextIO, text_stream) + # If the stream looks compatible, and won't default to a + # misconfigured ascii encoding, return it as-is. + if _is_compatible_text_stream(text_stream, encoding, errors) and not ( + encoding is None and _stream_is_misconfigured(text_stream) + ): + return text_stream + + # Otherwise, get the underlying binary reader. + possible_binary_reader = find_binary(text_stream) + + # If that's not possible, silently use the original reader + # and get mojibake instead of exceptions. + if possible_binary_reader is None: + return text_stream + + binary_reader = possible_binary_reader + + # Default errors to replace instead of strict in order to get + # something that works. + if errors is None: + errors = "replace" + + # Wrap the binary stream in a text stream with the correct + # encoding parameters. + return _make_text_stream( + binary_reader, + encoding, + errors, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def _force_correct_text_reader( + text_reader: t.IO, + encoding: t.Optional[str], + errors: t.Optional[str], + force_readable: bool = False, +) -> t.TextIO: + return _force_correct_text_stream( + text_reader, + encoding, + errors, + _is_binary_reader, + _find_binary_reader, + force_readable=force_readable, + ) + + +def _force_correct_text_writer( + text_writer: t.IO, + encoding: t.Optional[str], + errors: t.Optional[str], + force_writable: bool = False, +) -> t.TextIO: + return _force_correct_text_stream( + text_writer, + encoding, + errors, + _is_binary_writer, + _find_binary_writer, + force_writable=force_writable, + ) + + +def get_binary_stdin() -> t.BinaryIO: + reader = _find_binary_reader(sys.stdin) + if reader is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdin.") + return reader + + +def get_binary_stdout() -> t.BinaryIO: + writer = _find_binary_writer(sys.stdout) + if writer is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdout.") + return writer + + +def get_binary_stderr() -> t.BinaryIO: + writer = _find_binary_writer(sys.stderr) + if writer is None: + raise RuntimeError("Was not able to determine binary stream for sys.stderr.") + return writer + + +def get_text_stdin( + encoding: t.Optional[str] = None, errors: t.Optional[str] = None +) -> t.TextIO: + rv = _get_windows_console_stream(sys.stdin, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_reader(sys.stdin, encoding, errors, force_readable=True) + + +def get_text_stdout( + encoding: t.Optional[str] = None, errors: t.Optional[str] = None +) -> t.TextIO: + rv = _get_windows_console_stream(sys.stdout, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stdout, encoding, errors, force_writable=True) + + +def get_text_stderr( + encoding: t.Optional[str] = None, errors: t.Optional[str] = None +) -> t.TextIO: + rv = _get_windows_console_stream(sys.stderr, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stderr, encoding, errors, force_writable=True) + + +def _wrap_io_open( + file: t.Union[str, os.PathLike, int], + mode: str, + encoding: t.Optional[str], + errors: t.Optional[str], +) -> t.IO: + """Handles not passing ``encoding`` and ``errors`` in binary mode.""" + if "b" in mode: + return open(file, mode) + + return open(file, mode, encoding=encoding, errors=errors) + + +def open_stream( + filename: str, + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", + atomic: bool = False, +) -> t.Tuple[t.IO, bool]: + binary = "b" in mode + + # Standard streams first. These are simple because they ignore the + # atomic flag. Use fsdecode to handle Path("-"). + if os.fsdecode(filename) == "-": + if any(m in mode for m in ["w", "a", "x"]): + if binary: + return get_binary_stdout(), False + return get_text_stdout(encoding=encoding, errors=errors), False + if binary: + return get_binary_stdin(), False + return get_text_stdin(encoding=encoding, errors=errors), False + + # Non-atomic writes directly go out through the regular open functions. + if not atomic: + return _wrap_io_open(filename, mode, encoding, errors), True + + # Some usability stuff for atomic writes + if "a" in mode: + raise ValueError( + "Appending to an existing file is not supported, because that" + " would involve an expensive `copy`-operation to a temporary" + " file. Open the file in normal `w`-mode and copy explicitly" + " if that's what you're after." + ) + if "x" in mode: + raise ValueError("Use the `overwrite`-parameter instead.") + if "w" not in mode: + raise ValueError("Atomic writes only make sense with `w`-mode.") + + # Atomic writes are more complicated. They work by opening a file + # as a proxy in the same folder and then using the fdopen + # functionality to wrap it in a Python file. Then we wrap it in an + # atomic file that moves the file over on close. + import errno + import random + + try: + perm: t.Optional[int] = os.stat(filename).st_mode + except OSError: + perm = None + + flags = os.O_RDWR | os.O_CREAT | os.O_EXCL + + if binary: + flags |= getattr(os, "O_BINARY", 0) + + while True: + tmp_filename = os.path.join( + os.path.dirname(filename), + f".__atomic-write{random.randrange(1 << 32):08x}", + ) + try: + fd = os.open(tmp_filename, flags, 0o666 if perm is None else perm) + break + except OSError as e: + if e.errno == errno.EEXIST or ( + os.name == "nt" + and e.errno == errno.EACCES + and os.path.isdir(e.filename) + and os.access(e.filename, os.W_OK) + ): + continue + raise + + if perm is not None: + os.chmod(tmp_filename, perm) # in case perm includes bits in umask + + f = _wrap_io_open(fd, mode, encoding, errors) + af = _AtomicFile(f, tmp_filename, os.path.realpath(filename)) + return t.cast(t.IO, af), True + + +class _AtomicFile: + def __init__(self, f: t.IO, tmp_filename: str, real_filename: str) -> None: + self._f = f + self._tmp_filename = tmp_filename + self._real_filename = real_filename + self.closed = False + + @property + def name(self) -> str: + return self._real_filename + + def close(self, delete: bool = False) -> None: + if self.closed: + return + self._f.close() + os.replace(self._tmp_filename, self._real_filename) + self.closed = True + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._f, name) + + def __enter__(self) -> "_AtomicFile": + return self + + def __exit__(self, exc_type, exc_value, tb): # type: ignore + self.close(delete=exc_type is not None) + + def __repr__(self) -> str: + return repr(self._f) + + +def strip_ansi(value: str) -> str: + return _ansi_re.sub("", value) + + +def _is_jupyter_kernel_output(stream: t.IO) -> bool: + while isinstance(stream, (_FixupStream, _NonClosingTextIOWrapper)): + stream = stream._stream + + return stream.__class__.__module__.startswith("ipykernel.") + + +def should_strip_ansi( + stream: t.Optional[t.IO] = None, color: t.Optional[bool] = None +) -> bool: + if color is None: + if stream is None: + stream = sys.stdin + return not isatty(stream) and not _is_jupyter_kernel_output(stream) + return not color + + +# On Windows, wrap the output streams with colorama to support ANSI +# color codes. +# NOTE: double check is needed so mypy does not analyze this on Linux +if sys.platform.startswith("win") and WIN: + from ._winconsole import _get_windows_console_stream + + def _get_argv_encoding() -> str: + import locale + + return locale.getpreferredencoding() + + _ansi_stream_wrappers: t.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def auto_wrap_for_ansi( + stream: t.TextIO, color: t.Optional[bool] = None + ) -> t.TextIO: + """Support ANSI color and style codes on Windows by wrapping a + stream with colorama. + """ + try: + cached = _ansi_stream_wrappers.get(stream) + except Exception: + cached = None + + if cached is not None: + return cached + + import colorama + + strip = should_strip_ansi(stream, color) + ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip) + rv = t.cast(t.TextIO, ansi_wrapper.stream) + _write = rv.write + + def _safe_write(s): + try: + return _write(s) + except BaseException: + ansi_wrapper.reset_all() + raise + + rv.write = _safe_write + + try: + _ansi_stream_wrappers[stream] = rv + except Exception: + pass + + return rv + +else: + + def _get_argv_encoding() -> str: + return getattr(sys.stdin, "encoding", None) or get_filesystem_encoding() + + def _get_windows_console_stream( + f: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str] + ) -> t.Optional[t.TextIO]: + return None + + +def term_len(x: str) -> int: + return len(strip_ansi(x)) + + +def isatty(stream: t.IO) -> bool: + try: + return stream.isatty() + except Exception: + return False + + +def _make_cached_stream_func( + src_func: t.Callable[[], t.TextIO], wrapper_func: t.Callable[[], t.TextIO] +) -> t.Callable[[], t.TextIO]: + cache: t.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def func() -> t.TextIO: + stream = src_func() + try: + rv = cache.get(stream) + except Exception: + rv = None + if rv is not None: + return rv + rv = wrapper_func() + try: + cache[stream] = rv + except Exception: + pass + return rv + + return func + + +_default_text_stdin = _make_cached_stream_func(lambda: sys.stdin, get_text_stdin) +_default_text_stdout = _make_cached_stream_func(lambda: sys.stdout, get_text_stdout) +_default_text_stderr = _make_cached_stream_func(lambda: sys.stderr, get_text_stderr) + + +binary_streams: t.Mapping[str, t.Callable[[], t.BinaryIO]] = { + "stdin": get_binary_stdin, + "stdout": get_binary_stdout, + "stderr": get_binary_stderr, +} + +text_streams: t.Mapping[ + str, t.Callable[[t.Optional[str], t.Optional[str]], t.TextIO] +] = { + "stdin": get_text_stdin, + "stdout": get_text_stdout, + "stderr": get_text_stderr, +} diff --git a/.venv/Lib/site-packages/click/_termui_impl.py b/.venv/Lib/site-packages/click/_termui_impl.py new file mode 100644 index 000000000..4b979bcc1 --- /dev/null +++ b/.venv/Lib/site-packages/click/_termui_impl.py @@ -0,0 +1,717 @@ +""" +This module contains implementations for the termui module. To keep the +import time of Click down, some infrequently used functionality is +placed in this module and only imported as needed. +""" +import contextlib +import math +import os +import sys +import time +import typing as t +from gettext import gettext as _ + +from ._compat import _default_text_stdout +from ._compat import CYGWIN +from ._compat import get_best_encoding +from ._compat import isatty +from ._compat import open_stream +from ._compat import strip_ansi +from ._compat import term_len +from ._compat import WIN +from .exceptions import ClickException +from .utils import echo + +V = t.TypeVar("V") + +if os.name == "nt": + BEFORE_BAR = "\r" + AFTER_BAR = "\n" +else: + BEFORE_BAR = "\r\033[?25l" + AFTER_BAR = "\033[?25h\n" + + +class ProgressBar(t.Generic[V]): + def __init__( + self, + iterable: t.Optional[t.Iterable[V]], + length: t.Optional[int] = None, + fill_char: str = "#", + empty_char: str = " ", + bar_template: str = "%(bar)s", + info_sep: str = " ", + show_eta: bool = True, + show_percent: t.Optional[bool] = None, + show_pos: bool = False, + item_show_func: t.Optional[t.Callable[[t.Optional[V]], t.Optional[str]]] = None, + label: t.Optional[str] = None, + file: t.Optional[t.TextIO] = None, + color: t.Optional[bool] = None, + update_min_steps: int = 1, + width: int = 30, + ) -> None: + self.fill_char = fill_char + self.empty_char = empty_char + self.bar_template = bar_template + self.info_sep = info_sep + self.show_eta = show_eta + self.show_percent = show_percent + self.show_pos = show_pos + self.item_show_func = item_show_func + self.label = label or "" + if file is None: + file = _default_text_stdout() + self.file = file + self.color = color + self.update_min_steps = update_min_steps + self._completed_intervals = 0 + self.width = width + self.autowidth = width == 0 + + if length is None: + from operator import length_hint + + length = length_hint(iterable, -1) + + if length == -1: + length = None + if iterable is None: + if length is None: + raise TypeError("iterable or length is required") + iterable = t.cast(t.Iterable[V], range(length)) + self.iter = iter(iterable) + self.length = length + self.pos = 0 + self.avg: t.List[float] = [] + self.start = self.last_eta = time.time() + self.eta_known = False + self.finished = False + self.max_width: t.Optional[int] = None + self.entered = False + self.current_item: t.Optional[V] = None + self.is_hidden = not isatty(self.file) + self._last_line: t.Optional[str] = None + + def __enter__(self) -> "ProgressBar": + self.entered = True + self.render_progress() + return self + + def __exit__(self, exc_type, exc_value, tb): # type: ignore + self.render_finish() + + def __iter__(self) -> t.Iterator[V]: + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + self.render_progress() + return self.generator() + + def __next__(self) -> V: + # Iteration is defined in terms of a generator function, + # returned by iter(self); use that to define next(). This works + # because `self.iter` is an iterable consumed by that generator, + # so it is re-entry safe. Calling `next(self.generator())` + # twice works and does "what you want". + return next(iter(self)) + + def render_finish(self) -> None: + if self.is_hidden: + return + self.file.write(AFTER_BAR) + self.file.flush() + + @property + def pct(self) -> float: + if self.finished: + return 1.0 + return min(self.pos / (float(self.length or 1) or 1), 1.0) + + @property + def time_per_iteration(self) -> float: + if not self.avg: + return 0.0 + return sum(self.avg) / float(len(self.avg)) + + @property + def eta(self) -> float: + if self.length is not None and not self.finished: + return self.time_per_iteration * (self.length - self.pos) + return 0.0 + + def format_eta(self) -> str: + if self.eta_known: + t = int(self.eta) + seconds = t % 60 + t //= 60 + minutes = t % 60 + t //= 60 + hours = t % 24 + t //= 24 + if t > 0: + return f"{t}d {hours:02}:{minutes:02}:{seconds:02}" + else: + return f"{hours:02}:{minutes:02}:{seconds:02}" + return "" + + def format_pos(self) -> str: + pos = str(self.pos) + if self.length is not None: + pos += f"/{self.length}" + return pos + + def format_pct(self) -> str: + return f"{int(self.pct * 100): 4}%"[1:] + + def format_bar(self) -> str: + if self.length is not None: + bar_length = int(self.pct * self.width) + bar = self.fill_char * bar_length + bar += self.empty_char * (self.width - bar_length) + elif self.finished: + bar = self.fill_char * self.width + else: + chars = list(self.empty_char * (self.width or 1)) + if self.time_per_iteration != 0: + chars[ + int( + (math.cos(self.pos * self.time_per_iteration) / 2.0 + 0.5) + * self.width + ) + ] = self.fill_char + bar = "".join(chars) + return bar + + def format_progress_line(self) -> str: + show_percent = self.show_percent + + info_bits = [] + if self.length is not None and show_percent is None: + show_percent = not self.show_pos + + if self.show_pos: + info_bits.append(self.format_pos()) + if show_percent: + info_bits.append(self.format_pct()) + if self.show_eta and self.eta_known and not self.finished: + info_bits.append(self.format_eta()) + if self.item_show_func is not None: + item_info = self.item_show_func(self.current_item) + if item_info is not None: + info_bits.append(item_info) + + return ( + self.bar_template + % { + "label": self.label, + "bar": self.format_bar(), + "info": self.info_sep.join(info_bits), + } + ).rstrip() + + def render_progress(self) -> None: + import shutil + + if self.is_hidden: + # Only output the label as it changes if the output is not a + # TTY. Use file=stderr if you expect to be piping stdout. + if self._last_line != self.label: + self._last_line = self.label + echo(self.label, file=self.file, color=self.color) + + return + + buf = [] + # Update width in case the terminal has been resized + if self.autowidth: + old_width = self.width + self.width = 0 + clutter_length = term_len(self.format_progress_line()) + new_width = max(0, shutil.get_terminal_size().columns - clutter_length) + if new_width < old_width: + buf.append(BEFORE_BAR) + buf.append(" " * self.max_width) # type: ignore + self.max_width = new_width + self.width = new_width + + clear_width = self.width + if self.max_width is not None: + clear_width = self.max_width + + buf.append(BEFORE_BAR) + line = self.format_progress_line() + line_len = term_len(line) + if self.max_width is None or self.max_width < line_len: + self.max_width = line_len + + buf.append(line) + buf.append(" " * (clear_width - line_len)) + line = "".join(buf) + # Render the line only if it changed. + + if line != self._last_line: + self._last_line = line + echo(line, file=self.file, color=self.color, nl=False) + self.file.flush() + + def make_step(self, n_steps: int) -> None: + self.pos += n_steps + if self.length is not None and self.pos >= self.length: + self.finished = True + + if (time.time() - self.last_eta) < 1.0: + return + + self.last_eta = time.time() + + # self.avg is a rolling list of length <= 7 of steps where steps are + # defined as time elapsed divided by the total progress through + # self.length. + if self.pos: + step = (time.time() - self.start) / self.pos + else: + step = time.time() - self.start + + self.avg = self.avg[-6:] + [step] + + self.eta_known = self.length is not None + + def update(self, n_steps: int, current_item: t.Optional[V] = None) -> None: + """Update the progress bar by advancing a specified number of + steps, and optionally set the ``current_item`` for this new + position. + + :param n_steps: Number of steps to advance. + :param current_item: Optional item to set as ``current_item`` + for the updated position. + + .. versionchanged:: 8.0 + Added the ``current_item`` optional parameter. + + .. versionchanged:: 8.0 + Only render when the number of steps meets the + ``update_min_steps`` threshold. + """ + if current_item is not None: + self.current_item = current_item + + self._completed_intervals += n_steps + + if self._completed_intervals >= self.update_min_steps: + self.make_step(self._completed_intervals) + self.render_progress() + self._completed_intervals = 0 + + def finish(self) -> None: + self.eta_known = False + self.current_item = None + self.finished = True + + def generator(self) -> t.Iterator[V]: + """Return a generator which yields the items added to the bar + during construction, and updates the progress bar *after* the + yielded block returns. + """ + # WARNING: the iterator interface for `ProgressBar` relies on + # this and only works because this is a simple generator which + # doesn't create or manage additional state. If this function + # changes, the impact should be evaluated both against + # `iter(bar)` and `next(bar)`. `next()` in particular may call + # `self.generator()` repeatedly, and this must remain safe in + # order for that interface to work. + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + + if self.is_hidden: + yield from self.iter + else: + for rv in self.iter: + self.current_item = rv + + # This allows show_item_func to be updated before the + # item is processed. Only trigger at the beginning of + # the update interval. + if self._completed_intervals == 0: + self.render_progress() + + yield rv + self.update(1) + + self.finish() + self.render_progress() + + +def pager(generator: t.Iterable[str], color: t.Optional[bool] = None) -> None: + """Decide what method to use for paging through text.""" + stdout = _default_text_stdout() + if not isatty(sys.stdin) or not isatty(stdout): + return _nullpager(stdout, generator, color) + pager_cmd = (os.environ.get("PAGER", None) or "").strip() + if pager_cmd: + if WIN: + return _tempfilepager(generator, pager_cmd, color) + return _pipepager(generator, pager_cmd, color) + if os.environ.get("TERM") in ("dumb", "emacs"): + return _nullpager(stdout, generator, color) + if WIN or sys.platform.startswith("os2"): + return _tempfilepager(generator, "more <", color) + if hasattr(os, "system") and os.system("(less) 2>/dev/null") == 0: + return _pipepager(generator, "less", color) + + import tempfile + + fd, filename = tempfile.mkstemp() + os.close(fd) + try: + if hasattr(os, "system") and os.system(f'more "{filename}"') == 0: + return _pipepager(generator, "more", color) + return _nullpager(stdout, generator, color) + finally: + os.unlink(filename) + + +def _pipepager(generator: t.Iterable[str], cmd: str, color: t.Optional[bool]) -> None: + """Page through text by feeding it to another program. Invoking a + pager through this might support colors. + """ + import subprocess + + env = dict(os.environ) + + # If we're piping to less we might support colors under the + # condition that + cmd_detail = cmd.rsplit("/", 1)[-1].split() + if color is None and cmd_detail[0] == "less": + less_flags = f"{os.environ.get('LESS', '')}{' '.join(cmd_detail[1:])}" + if not less_flags: + env["LESS"] = "-R" + color = True + elif "r" in less_flags or "R" in less_flags: + color = True + + c = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, env=env) + stdin = t.cast(t.BinaryIO, c.stdin) + encoding = get_best_encoding(stdin) + try: + for text in generator: + if not color: + text = strip_ansi(text) + + stdin.write(text.encode(encoding, "replace")) + except (OSError, KeyboardInterrupt): + pass + else: + stdin.close() + + # Less doesn't respect ^C, but catches it for its own UI purposes (aborting + # search or other commands inside less). + # + # That means when the user hits ^C, the parent process (click) terminates, + # but less is still alive, paging the output and messing up the terminal. + # + # If the user wants to make the pager exit on ^C, they should set + # `LESS='-K'`. It's not our decision to make. + while True: + try: + c.wait() + except KeyboardInterrupt: + pass + else: + break + + +def _tempfilepager( + generator: t.Iterable[str], cmd: str, color: t.Optional[bool] +) -> None: + """Page through text by invoking a program on a temporary file.""" + import tempfile + + fd, filename = tempfile.mkstemp() + # TODO: This never terminates if the passed generator never terminates. + text = "".join(generator) + if not color: + text = strip_ansi(text) + encoding = get_best_encoding(sys.stdout) + with open_stream(filename, "wb")[0] as f: + f.write(text.encode(encoding)) + try: + os.system(f'{cmd} "{filename}"') + finally: + os.close(fd) + os.unlink(filename) + + +def _nullpager( + stream: t.TextIO, generator: t.Iterable[str], color: t.Optional[bool] +) -> None: + """Simply print unformatted text. This is the ultimate fallback.""" + for text in generator: + if not color: + text = strip_ansi(text) + stream.write(text) + + +class Editor: + def __init__( + self, + editor: t.Optional[str] = None, + env: t.Optional[t.Mapping[str, str]] = None, + require_save: bool = True, + extension: str = ".txt", + ) -> None: + self.editor = editor + self.env = env + self.require_save = require_save + self.extension = extension + + def get_editor(self) -> str: + if self.editor is not None: + return self.editor + for key in "VISUAL", "EDITOR": + rv = os.environ.get(key) + if rv: + return rv + if WIN: + return "notepad" + for editor in "sensible-editor", "vim", "nano": + if os.system(f"which {editor} >/dev/null 2>&1") == 0: + return editor + return "vi" + + def edit_file(self, filename: str) -> None: + import subprocess + + editor = self.get_editor() + environ: t.Optional[t.Dict[str, str]] = None + + if self.env: + environ = os.environ.copy() + environ.update(self.env) + + try: + c = subprocess.Popen(f'{editor} "{filename}"', env=environ, shell=True) + exit_code = c.wait() + if exit_code != 0: + raise ClickException( + _("{editor}: Editing failed").format(editor=editor) + ) + except OSError as e: + raise ClickException( + _("{editor}: Editing failed: {e}").format(editor=editor, e=e) + ) from e + + def edit(self, text: t.Optional[t.AnyStr]) -> t.Optional[t.AnyStr]: + import tempfile + + if not text: + data = b"" + elif isinstance(text, (bytes, bytearray)): + data = text + else: + if text and not text.endswith("\n"): + text += "\n" + + if WIN: + data = text.replace("\n", "\r\n").encode("utf-8-sig") + else: + data = text.encode("utf-8") + + fd, name = tempfile.mkstemp(prefix="editor-", suffix=self.extension) + f: t.BinaryIO + + try: + with os.fdopen(fd, "wb") as f: + f.write(data) + + # If the filesystem resolution is 1 second, like Mac OS + # 10.12 Extended, or 2 seconds, like FAT32, and the editor + # closes very fast, require_save can fail. Set the modified + # time to be 2 seconds in the past to work around this. + os.utime(name, (os.path.getatime(name), os.path.getmtime(name) - 2)) + # Depending on the resolution, the exact value might not be + # recorded, so get the new recorded value. + timestamp = os.path.getmtime(name) + + self.edit_file(name) + + if self.require_save and os.path.getmtime(name) == timestamp: + return None + + with open(name, "rb") as f: + rv = f.read() + + if isinstance(text, (bytes, bytearray)): + return rv + + return rv.decode("utf-8-sig").replace("\r\n", "\n") # type: ignore + finally: + os.unlink(name) + + +def open_url(url: str, wait: bool = False, locate: bool = False) -> int: + import subprocess + + def _unquote_file(url: str) -> str: + from urllib.parse import unquote + + if url.startswith("file://"): + url = unquote(url[7:]) + + return url + + if sys.platform == "darwin": + args = ["open"] + if wait: + args.append("-W") + if locate: + args.append("-R") + args.append(_unquote_file(url)) + null = open("/dev/null", "w") + try: + return subprocess.Popen(args, stderr=null).wait() + finally: + null.close() + elif WIN: + if locate: + url = _unquote_file(url.replace('"', "")) + args = f'explorer /select,"{url}"' + else: + url = url.replace('"', "") + wait_str = "/WAIT" if wait else "" + args = f'start {wait_str} "" "{url}"' + return os.system(args) + elif CYGWIN: + if locate: + url = os.path.dirname(_unquote_file(url).replace('"', "")) + args = f'cygstart "{url}"' + else: + url = url.replace('"', "") + wait_str = "-w" if wait else "" + args = f'cygstart {wait_str} "{url}"' + return os.system(args) + + try: + if locate: + url = os.path.dirname(_unquote_file(url)) or "." + else: + url = _unquote_file(url) + c = subprocess.Popen(["xdg-open", url]) + if wait: + return c.wait() + return 0 + except OSError: + if url.startswith(("http://", "https://")) and not locate and not wait: + import webbrowser + + webbrowser.open(url) + return 0 + return 1 + + +def _translate_ch_to_exc(ch: str) -> t.Optional[BaseException]: + if ch == "\x03": + raise KeyboardInterrupt() + + if ch == "\x04" and not WIN: # Unix-like, Ctrl+D + raise EOFError() + + if ch == "\x1a" and WIN: # Windows, Ctrl+Z + raise EOFError() + + return None + + +if WIN: + import msvcrt + + @contextlib.contextmanager + def raw_terminal() -> t.Iterator[int]: + yield -1 + + def getchar(echo: bool) -> str: + # The function `getch` will return a bytes object corresponding to + # the pressed character. Since Windows 10 build 1803, it will also + # return \x00 when called a second time after pressing a regular key. + # + # `getwch` does not share this probably-bugged behavior. Moreover, it + # returns a Unicode object by default, which is what we want. + # + # Either of these functions will return \x00 or \xe0 to indicate + # a special key, and you need to call the same function again to get + # the "rest" of the code. The fun part is that \u00e0 is + # "latin small letter a with grave", so if you type that on a French + # keyboard, you _also_ get a \xe0. + # E.g., consider the Up arrow. This returns \xe0 and then \x48. The + # resulting Unicode string reads as "a with grave" + "capital H". + # This is indistinguishable from when the user actually types + # "a with grave" and then "capital H". + # + # When \xe0 is returned, we assume it's part of a special-key sequence + # and call `getwch` again, but that means that when the user types + # the \u00e0 character, `getchar` doesn't return until a second + # character is typed. + # The alternative is returning immediately, but that would mess up + # cross-platform handling of arrow keys and others that start with + # \xe0. Another option is using `getch`, but then we can't reliably + # read non-ASCII characters, because return values of `getch` are + # limited to the current 8-bit codepage. + # + # Anyway, Click doesn't claim to do this Right(tm), and using `getwch` + # is doing the right thing in more situations than with `getch`. + func: t.Callable[[], str] + + if echo: + func = msvcrt.getwche # type: ignore + else: + func = msvcrt.getwch # type: ignore + + rv = func() + + if rv in ("\x00", "\xe0"): + # \x00 and \xe0 are control characters that indicate special key, + # see above. + rv += func() + + _translate_ch_to_exc(rv) + return rv + +else: + import tty + import termios + + @contextlib.contextmanager + def raw_terminal() -> t.Iterator[int]: + f: t.Optional[t.TextIO] + fd: int + + if not isatty(sys.stdin): + f = open("/dev/tty") + fd = f.fileno() + else: + fd = sys.stdin.fileno() + f = None + + try: + old_settings = termios.tcgetattr(fd) + + try: + tty.setraw(fd) + yield fd + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + sys.stdout.flush() + + if f is not None: + f.close() + except termios.error: + pass + + def getchar(echo: bool) -> str: + with raw_terminal() as fd: + ch = os.read(fd, 32).decode(get_best_encoding(sys.stdin), "replace") + + if echo and isatty(sys.stdout): + sys.stdout.write(ch) + + _translate_ch_to_exc(ch) + return ch diff --git a/.venv/Lib/site-packages/click/_textwrap.py b/.venv/Lib/site-packages/click/_textwrap.py new file mode 100644 index 000000000..b47dcbd42 --- /dev/null +++ b/.venv/Lib/site-packages/click/_textwrap.py @@ -0,0 +1,49 @@ +import textwrap +import typing as t +from contextlib import contextmanager + + +class TextWrapper(textwrap.TextWrapper): + def _handle_long_word( + self, + reversed_chunks: t.List[str], + cur_line: t.List[str], + cur_len: int, + width: int, + ) -> None: + space_left = max(width - cur_len, 1) + + if self.break_long_words: + last = reversed_chunks[-1] + cut = last[:space_left] + res = last[space_left:] + cur_line.append(cut) + reversed_chunks[-1] = res + elif not cur_line: + cur_line.append(reversed_chunks.pop()) + + @contextmanager + def extra_indent(self, indent: str) -> t.Iterator[None]: + old_initial_indent = self.initial_indent + old_subsequent_indent = self.subsequent_indent + self.initial_indent += indent + self.subsequent_indent += indent + + try: + yield + finally: + self.initial_indent = old_initial_indent + self.subsequent_indent = old_subsequent_indent + + def indent_only(self, text: str) -> str: + rv = [] + + for idx, line in enumerate(text.splitlines()): + indent = self.initial_indent + + if idx > 0: + indent = self.subsequent_indent + + rv.append(f"{indent}{line}") + + return "\n".join(rv) diff --git a/.venv/Lib/site-packages/click/_winconsole.py b/.venv/Lib/site-packages/click/_winconsole.py new file mode 100644 index 000000000..6b20df315 --- /dev/null +++ b/.venv/Lib/site-packages/click/_winconsole.py @@ -0,0 +1,279 @@ +# This module is based on the excellent work by Adam Bartoš who +# provided a lot of what went into the implementation here in +# the discussion to issue1602 in the Python bug tracker. +# +# There are some general differences in regards to how this works +# compared to the original patches as we do not need to patch +# the entire interpreter but just work in our little world of +# echo and prompt. +import io +import sys +import time +import typing as t +from ctypes import byref +from ctypes import c_char +from ctypes import c_char_p +from ctypes import c_int +from ctypes import c_ssize_t +from ctypes import c_ulong +from ctypes import c_void_p +from ctypes import POINTER +from ctypes import py_object +from ctypes import Structure +from ctypes.wintypes import DWORD +from ctypes.wintypes import HANDLE +from ctypes.wintypes import LPCWSTR +from ctypes.wintypes import LPWSTR + +from ._compat import _NonClosingTextIOWrapper + +assert sys.platform == "win32" +import msvcrt # noqa: E402 +from ctypes import windll # noqa: E402 +from ctypes import WINFUNCTYPE # noqa: E402 + +c_ssize_p = POINTER(c_ssize_t) + +kernel32 = windll.kernel32 +GetStdHandle = kernel32.GetStdHandle +ReadConsoleW = kernel32.ReadConsoleW +WriteConsoleW = kernel32.WriteConsoleW +GetConsoleMode = kernel32.GetConsoleMode +GetLastError = kernel32.GetLastError +GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32)) +CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( + ("CommandLineToArgvW", windll.shell32) +) +LocalFree = WINFUNCTYPE(c_void_p, c_void_p)(("LocalFree", windll.kernel32)) + +STDIN_HANDLE = GetStdHandle(-10) +STDOUT_HANDLE = GetStdHandle(-11) +STDERR_HANDLE = GetStdHandle(-12) + +PyBUF_SIMPLE = 0 +PyBUF_WRITABLE = 1 + +ERROR_SUCCESS = 0 +ERROR_NOT_ENOUGH_MEMORY = 8 +ERROR_OPERATION_ABORTED = 995 + +STDIN_FILENO = 0 +STDOUT_FILENO = 1 +STDERR_FILENO = 2 + +EOF = b"\x1a" +MAX_BYTES_WRITTEN = 32767 + +try: + from ctypes import pythonapi +except ImportError: + # On PyPy we cannot get buffers so our ability to operate here is + # severely limited. + get_buffer = None +else: + + class Py_buffer(Structure): + _fields_ = [ + ("buf", c_void_p), + ("obj", py_object), + ("len", c_ssize_t), + ("itemsize", c_ssize_t), + ("readonly", c_int), + ("ndim", c_int), + ("format", c_char_p), + ("shape", c_ssize_p), + ("strides", c_ssize_p), + ("suboffsets", c_ssize_p), + ("internal", c_void_p), + ] + + PyObject_GetBuffer = pythonapi.PyObject_GetBuffer + PyBuffer_Release = pythonapi.PyBuffer_Release + + def get_buffer(obj, writable=False): + buf = Py_buffer() + flags = PyBUF_WRITABLE if writable else PyBUF_SIMPLE + PyObject_GetBuffer(py_object(obj), byref(buf), flags) + + try: + buffer_type = c_char * buf.len + return buffer_type.from_address(buf.buf) + finally: + PyBuffer_Release(byref(buf)) + + +class _WindowsConsoleRawIOBase(io.RawIOBase): + def __init__(self, handle): + self.handle = handle + + def isatty(self): + super().isatty() + return True + + +class _WindowsConsoleReader(_WindowsConsoleRawIOBase): + def readable(self): + return True + + def readinto(self, b): + bytes_to_be_read = len(b) + if not bytes_to_be_read: + return 0 + elif bytes_to_be_read % 2: + raise ValueError( + "cannot read odd number of bytes from UTF-16-LE encoded console" + ) + + buffer = get_buffer(b, writable=True) + code_units_to_be_read = bytes_to_be_read // 2 + code_units_read = c_ulong() + + rv = ReadConsoleW( + HANDLE(self.handle), + buffer, + code_units_to_be_read, + byref(code_units_read), + None, + ) + if GetLastError() == ERROR_OPERATION_ABORTED: + # wait for KeyboardInterrupt + time.sleep(0.1) + if not rv: + raise OSError(f"Windows error: {GetLastError()}") + + if buffer[0] == EOF: + return 0 + return 2 * code_units_read.value + + +class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): + def writable(self): + return True + + @staticmethod + def _get_error_message(errno): + if errno == ERROR_SUCCESS: + return "ERROR_SUCCESS" + elif errno == ERROR_NOT_ENOUGH_MEMORY: + return "ERROR_NOT_ENOUGH_MEMORY" + return f"Windows error {errno}" + + def write(self, b): + bytes_to_be_written = len(b) + buf = get_buffer(b) + code_units_to_be_written = min(bytes_to_be_written, MAX_BYTES_WRITTEN) // 2 + code_units_written = c_ulong() + + WriteConsoleW( + HANDLE(self.handle), + buf, + code_units_to_be_written, + byref(code_units_written), + None, + ) + bytes_written = 2 * code_units_written.value + + if bytes_written == 0 and bytes_to_be_written > 0: + raise OSError(self._get_error_message(GetLastError())) + return bytes_written + + +class ConsoleStream: + def __init__(self, text_stream: t.TextIO, byte_stream: t.BinaryIO) -> None: + self._text_stream = text_stream + self.buffer = byte_stream + + @property + def name(self) -> str: + return self.buffer.name + + def write(self, x: t.AnyStr) -> int: + if isinstance(x, str): + return self._text_stream.write(x) + try: + self.flush() + except Exception: + pass + return self.buffer.write(x) + + def writelines(self, lines: t.Iterable[t.AnyStr]) -> None: + for line in lines: + self.write(line) + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._text_stream, name) + + def isatty(self) -> bool: + return self.buffer.isatty() + + def __repr__(self): + return f"" + + +def _get_text_stdin(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +def _get_text_stdout(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDOUT_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +def _get_text_stderr(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDERR_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +_stream_factories: t.Mapping[int, t.Callable[[t.BinaryIO], t.TextIO]] = { + 0: _get_text_stdin, + 1: _get_text_stdout, + 2: _get_text_stderr, +} + + +def _is_console(f: t.TextIO) -> bool: + if not hasattr(f, "fileno"): + return False + + try: + fileno = f.fileno() + except (OSError, io.UnsupportedOperation): + return False + + handle = msvcrt.get_osfhandle(fileno) + return bool(GetConsoleMode(handle, byref(DWORD()))) + + +def _get_windows_console_stream( + f: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str] +) -> t.Optional[t.TextIO]: + if ( + get_buffer is not None + and encoding in {"utf-16-le", None} + and errors in {"strict", None} + and _is_console(f) + ): + func = _stream_factories.get(f.fileno()) + if func is not None: + b = getattr(f, "buffer", None) + + if b is None: + return None + + return func(b) diff --git a/.venv/Lib/site-packages/click/core.py b/.venv/Lib/site-packages/click/core.py new file mode 100644 index 000000000..5abfb0f3c --- /dev/null +++ b/.venv/Lib/site-packages/click/core.py @@ -0,0 +1,2998 @@ +import enum +import errno +import inspect +import os +import sys +import typing as t +from collections import abc +from contextlib import contextmanager +from contextlib import ExitStack +from functools import partial +from functools import update_wrapper +from gettext import gettext as _ +from gettext import ngettext +from itertools import repeat + +from . import types +from .exceptions import Abort +from .exceptions import BadParameter +from .exceptions import ClickException +from .exceptions import Exit +from .exceptions import MissingParameter +from .exceptions import UsageError +from .formatting import HelpFormatter +from .formatting import join_options +from .globals import pop_context +from .globals import push_context +from .parser import _flag_needs_value +from .parser import OptionParser +from .parser import split_opt +from .termui import confirm +from .termui import prompt +from .termui import style +from .utils import _detect_program_name +from .utils import _expand_args +from .utils import echo +from .utils import make_default_short_help +from .utils import make_str +from .utils import PacifyFlushWrapper + +if t.TYPE_CHECKING: + import typing_extensions as te + from .shell_completion import CompletionItem + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) +V = t.TypeVar("V") + + +def _complete_visible_commands( + ctx: "Context", incomplete: str +) -> t.Iterator[t.Tuple[str, "Command"]]: + """List all the subcommands of a group that start with the + incomplete value and aren't hidden. + + :param ctx: Invocation context for the group. + :param incomplete: Value being completed. May be empty. + """ + multi = t.cast(MultiCommand, ctx.command) + + for name in multi.list_commands(ctx): + if name.startswith(incomplete): + command = multi.get_command(ctx, name) + + if command is not None and not command.hidden: + yield name, command + + +def _check_multicommand( + base_command: "MultiCommand", cmd_name: str, cmd: "Command", register: bool = False +) -> None: + if not base_command.chain or not isinstance(cmd, MultiCommand): + return + if register: + hint = ( + "It is not possible to add multi commands as children to" + " another multi command that is in chain mode." + ) + else: + hint = ( + "Found a multi command as subcommand to a multi command" + " that is in chain mode. This is not supported." + ) + raise RuntimeError( + f"{hint}. Command {base_command.name!r} is set to chain and" + f" {cmd_name!r} was added as a subcommand but it in itself is a" + f" multi command. ({cmd_name!r} is a {type(cmd).__name__}" + f" within a chained {type(base_command).__name__} named" + f" {base_command.name!r})." + ) + + +def batch(iterable: t.Iterable[V], batch_size: int) -> t.List[t.Tuple[V, ...]]: + return list(zip(*repeat(iter(iterable), batch_size))) + + +@contextmanager +def augment_usage_errors( + ctx: "Context", param: t.Optional["Parameter"] = None +) -> t.Iterator[None]: + """Context manager that attaches extra information to exceptions.""" + try: + yield + except BadParameter as e: + if e.ctx is None: + e.ctx = ctx + if param is not None and e.param is None: + e.param = param + raise + except UsageError as e: + if e.ctx is None: + e.ctx = ctx + raise + + +def iter_params_for_processing( + invocation_order: t.Sequence["Parameter"], + declaration_order: t.Sequence["Parameter"], +) -> t.List["Parameter"]: + """Given a sequence of parameters in the order as should be considered + for processing and an iterable of parameters that exist, this returns + a list in the correct order as they should be processed. + """ + + def sort_key(item: "Parameter") -> t.Tuple[bool, float]: + try: + idx: float = invocation_order.index(item) + except ValueError: + idx = float("inf") + + return not item.is_eager, idx + + return sorted(declaration_order, key=sort_key) + + +class ParameterSource(enum.Enum): + """This is an :class:`~enum.Enum` that indicates the source of a + parameter's value. + + Use :meth:`click.Context.get_parameter_source` to get the + source for a parameter by name. + + .. versionchanged:: 8.0 + Use :class:`~enum.Enum` and drop the ``validate`` method. + + .. versionchanged:: 8.0 + Added the ``PROMPT`` value. + """ + + COMMANDLINE = enum.auto() + """The value was provided by the command line args.""" + ENVIRONMENT = enum.auto() + """The value was provided with an environment variable.""" + DEFAULT = enum.auto() + """Used the default specified by the parameter.""" + DEFAULT_MAP = enum.auto() + """Used a default provided by :attr:`Context.default_map`.""" + PROMPT = enum.auto() + """Used a prompt to confirm a default or provide a value.""" + + +class Context: + """The context is a special internal object that holds state relevant + for the script execution at every single level. It's normally invisible + to commands unless they opt-in to getting access to it. + + The context is useful as it can pass internal objects around and can + control special execution features such as reading data from + environment variables. + + A context can be used as context manager in which case it will call + :meth:`close` on teardown. + + :param command: the command class for this context. + :param parent: the parent context. + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it is usually + the name of the script, for commands below it it's + the name of the script. + :param obj: an arbitrary object of user data. + :param auto_envvar_prefix: the prefix to use for automatic environment + variables. If this is `None` then reading + from environment variables is disabled. This + does not affect manually set environment + variables which are always read. + :param default_map: a dictionary (like object) with default values + for parameters. + :param terminal_width: the width of the terminal. The default is + inherit from parent context. If no context + defines the terminal width then auto + detection will be applied. + :param max_content_width: the maximum width for content rendered by + Click (this currently only affects help + pages). This defaults to 80 characters if + not overridden. In other words: even if the + terminal is larger than that, Click will not + format things wider than 80 characters by + default. In addition to that, formatters might + add some safety mapping on the right. + :param resilient_parsing: if this flag is enabled then Click will + parse without any interactivity or callback + invocation. Default values will also be + ignored. This is useful for implementing + things such as completion support. + :param allow_extra_args: if this is set to `True` then extra arguments + at the end will not raise an error and will be + kept on the context. The default is to inherit + from the command. + :param allow_interspersed_args: if this is set to `False` then options + and arguments cannot be mixed. The + default is to inherit from the command. + :param ignore_unknown_options: instructs click to ignore options it does + not know and keeps them for later + processing. + :param help_option_names: optionally a list of strings that define how + the default help parameter is named. The + default is ``['--help']``. + :param token_normalize_func: an optional function that is used to + normalize tokens (options, choices, + etc.). This for instance can be used to + implement case insensitive behavior. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are used in texts that Click prints which is by + default not the case. This for instance would affect + help output. + :param show_default: Show the default value for commands. If this + value is not set, it defaults to the value from the parent + context. ``Command.show_default`` overrides this default for the + specific command. + + .. versionchanged:: 8.1 + The ``show_default`` parameter is overridden by + ``Command.show_default``, instead of the other way around. + + .. versionchanged:: 8.0 + The ``show_default`` parameter defaults to the value from the + parent context. + + .. versionchanged:: 7.1 + Added the ``show_default`` parameter. + + .. versionchanged:: 4.0 + Added the ``color``, ``ignore_unknown_options``, and + ``max_content_width`` parameters. + + .. versionchanged:: 3.0 + Added the ``allow_extra_args`` and ``allow_interspersed_args`` + parameters. + + .. versionchanged:: 2.0 + Added the ``resilient_parsing``, ``help_option_names``, and + ``token_normalize_func`` parameters. + """ + + #: The formatter class to create with :meth:`make_formatter`. + #: + #: .. versionadded:: 8.0 + formatter_class: t.Type["HelpFormatter"] = HelpFormatter + + def __init__( + self, + command: "Command", + parent: t.Optional["Context"] = None, + info_name: t.Optional[str] = None, + obj: t.Optional[t.Any] = None, + auto_envvar_prefix: t.Optional[str] = None, + default_map: t.Optional[t.Dict[str, t.Any]] = None, + terminal_width: t.Optional[int] = None, + max_content_width: t.Optional[int] = None, + resilient_parsing: bool = False, + allow_extra_args: t.Optional[bool] = None, + allow_interspersed_args: t.Optional[bool] = None, + ignore_unknown_options: t.Optional[bool] = None, + help_option_names: t.Optional[t.List[str]] = None, + token_normalize_func: t.Optional[t.Callable[[str], str]] = None, + color: t.Optional[bool] = None, + show_default: t.Optional[bool] = None, + ) -> None: + #: the parent context or `None` if none exists. + self.parent = parent + #: the :class:`Command` for this context. + self.command = command + #: the descriptive information name + self.info_name = info_name + #: Map of parameter names to their parsed values. Parameters + #: with ``expose_value=False`` are not stored. + self.params: t.Dict[str, t.Any] = {} + #: the leftover arguments. + self.args: t.List[str] = [] + #: protected arguments. These are arguments that are prepended + #: to `args` when certain parsing scenarios are encountered but + #: must be never propagated to another arguments. This is used + #: to implement nested parsing. + self.protected_args: t.List[str] = [] + #: the collected prefixes of the command's options. + self._opt_prefixes: t.Set[str] = set(parent._opt_prefixes) if parent else set() + + if obj is None and parent is not None: + obj = parent.obj + + #: the user object stored. + self.obj: t.Any = obj + self._meta: t.Dict[str, t.Any] = getattr(parent, "meta", {}) + + #: A dictionary (-like object) with defaults for parameters. + if ( + default_map is None + and info_name is not None + and parent is not None + and parent.default_map is not None + ): + default_map = parent.default_map.get(info_name) + + self.default_map: t.Optional[t.Dict[str, t.Any]] = default_map + + #: This flag indicates if a subcommand is going to be executed. A + #: group callback can use this information to figure out if it's + #: being executed directly or because the execution flow passes + #: onwards to a subcommand. By default it's None, but it can be + #: the name of the subcommand to execute. + #: + #: If chaining is enabled this will be set to ``'*'`` in case + #: any commands are executed. It is however not possible to + #: figure out which ones. If you require this knowledge you + #: should use a :func:`result_callback`. + self.invoked_subcommand: t.Optional[str] = None + + if terminal_width is None and parent is not None: + terminal_width = parent.terminal_width + + #: The width of the terminal (None is autodetection). + self.terminal_width: t.Optional[int] = terminal_width + + if max_content_width is None and parent is not None: + max_content_width = parent.max_content_width + + #: The maximum width of formatted content (None implies a sensible + #: default which is 80 for most things). + self.max_content_width: t.Optional[int] = max_content_width + + if allow_extra_args is None: + allow_extra_args = command.allow_extra_args + + #: Indicates if the context allows extra args or if it should + #: fail on parsing. + #: + #: .. versionadded:: 3.0 + self.allow_extra_args = allow_extra_args + + if allow_interspersed_args is None: + allow_interspersed_args = command.allow_interspersed_args + + #: Indicates if the context allows mixing of arguments and + #: options or not. + #: + #: .. versionadded:: 3.0 + self.allow_interspersed_args: bool = allow_interspersed_args + + if ignore_unknown_options is None: + ignore_unknown_options = command.ignore_unknown_options + + #: Instructs click to ignore options that a command does not + #: understand and will store it on the context for later + #: processing. This is primarily useful for situations where you + #: want to call into external programs. Generally this pattern is + #: strongly discouraged because it's not possibly to losslessly + #: forward all arguments. + #: + #: .. versionadded:: 4.0 + self.ignore_unknown_options: bool = ignore_unknown_options + + if help_option_names is None: + if parent is not None: + help_option_names = parent.help_option_names + else: + help_option_names = ["--help"] + + #: The names for the help options. + self.help_option_names: t.List[str] = help_option_names + + if token_normalize_func is None and parent is not None: + token_normalize_func = parent.token_normalize_func + + #: An optional normalization function for tokens. This is + #: options, choices, commands etc. + self.token_normalize_func: t.Optional[ + t.Callable[[str], str] + ] = token_normalize_func + + #: Indicates if resilient parsing is enabled. In that case Click + #: will do its best to not cause any failures and default values + #: will be ignored. Useful for completion. + self.resilient_parsing: bool = resilient_parsing + + # If there is no envvar prefix yet, but the parent has one and + # the command on this level has a name, we can expand the envvar + # prefix automatically. + if auto_envvar_prefix is None: + if ( + parent is not None + and parent.auto_envvar_prefix is not None + and self.info_name is not None + ): + auto_envvar_prefix = ( + f"{parent.auto_envvar_prefix}_{self.info_name.upper()}" + ) + else: + auto_envvar_prefix = auto_envvar_prefix.upper() + + if auto_envvar_prefix is not None: + auto_envvar_prefix = auto_envvar_prefix.replace("-", "_") + + self.auto_envvar_prefix: t.Optional[str] = auto_envvar_prefix + + if color is None and parent is not None: + color = parent.color + + #: Controls if styling output is wanted or not. + self.color: t.Optional[bool] = color + + if show_default is None and parent is not None: + show_default = parent.show_default + + #: Show option default values when formatting help text. + self.show_default: t.Optional[bool] = show_default + + self._close_callbacks: t.List[t.Callable[[], t.Any]] = [] + self._depth = 0 + self._parameter_source: t.Dict[str, ParameterSource] = {} + self._exit_stack = ExitStack() + + def to_info_dict(self) -> t.Dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. This traverses the entire CLI + structure. + + .. code-block:: python + + with Context(cli) as ctx: + info = ctx.to_info_dict() + + .. versionadded:: 8.0 + """ + return { + "command": self.command.to_info_dict(self), + "info_name": self.info_name, + "allow_extra_args": self.allow_extra_args, + "allow_interspersed_args": self.allow_interspersed_args, + "ignore_unknown_options": self.ignore_unknown_options, + "auto_envvar_prefix": self.auto_envvar_prefix, + } + + def __enter__(self) -> "Context": + self._depth += 1 + push_context(self) + return self + + def __exit__(self, exc_type, exc_value, tb): # type: ignore + self._depth -= 1 + if self._depth == 0: + self.close() + pop_context() + + @contextmanager + def scope(self, cleanup: bool = True) -> t.Iterator["Context"]: + """This helper method can be used with the context object to promote + it to the current thread local (see :func:`get_current_context`). + The default behavior of this is to invoke the cleanup functions which + can be disabled by setting `cleanup` to `False`. The cleanup + functions are typically used for things such as closing file handles. + + If the cleanup is intended the context object can also be directly + used as a context manager. + + Example usage:: + + with ctx.scope(): + assert get_current_context() is ctx + + This is equivalent:: + + with ctx: + assert get_current_context() is ctx + + .. versionadded:: 5.0 + + :param cleanup: controls if the cleanup functions should be run or + not. The default is to run these functions. In + some situations the context only wants to be + temporarily pushed in which case this can be disabled. + Nested pushes automatically defer the cleanup. + """ + if not cleanup: + self._depth += 1 + try: + with self as rv: + yield rv + finally: + if not cleanup: + self._depth -= 1 + + @property + def meta(self) -> t.Dict[str, t.Any]: + """This is a dictionary which is shared with all the contexts + that are nested. It exists so that click utilities can store some + state here if they need to. It is however the responsibility of + that code to manage this dictionary well. + + The keys are supposed to be unique dotted strings. For instance + module paths are a good choice for it. What is stored in there is + irrelevant for the operation of click. However what is important is + that code that places data here adheres to the general semantics of + the system. + + Example usage:: + + LANG_KEY = f'{__name__}.lang' + + def set_language(value): + ctx = get_current_context() + ctx.meta[LANG_KEY] = value + + def get_language(): + return get_current_context().meta.get(LANG_KEY, 'en_US') + + .. versionadded:: 5.0 + """ + return self._meta + + def make_formatter(self) -> HelpFormatter: + """Creates the :class:`~click.HelpFormatter` for the help and + usage output. + + To quickly customize the formatter class used without overriding + this method, set the :attr:`formatter_class` attribute. + + .. versionchanged:: 8.0 + Added the :attr:`formatter_class` attribute. + """ + return self.formatter_class( + width=self.terminal_width, max_width=self.max_content_width + ) + + def with_resource(self, context_manager: t.ContextManager[V]) -> V: + """Register a resource as if it were used in a ``with`` + statement. The resource will be cleaned up when the context is + popped. + + Uses :meth:`contextlib.ExitStack.enter_context`. It calls the + resource's ``__enter__()`` method and returns the result. When + the context is popped, it closes the stack, which calls the + resource's ``__exit__()`` method. + + To register a cleanup function for something that isn't a + context manager, use :meth:`call_on_close`. Or use something + from :mod:`contextlib` to turn it into a context manager first. + + .. code-block:: python + + @click.group() + @click.option("--name") + @click.pass_context + def cli(ctx): + ctx.obj = ctx.with_resource(connect_db(name)) + + :param context_manager: The context manager to enter. + :return: Whatever ``context_manager.__enter__()`` returns. + + .. versionadded:: 8.0 + """ + return self._exit_stack.enter_context(context_manager) + + def call_on_close(self, f: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]: + """Register a function to be called when the context tears down. + + This can be used to close resources opened during the script + execution. Resources that support Python's context manager + protocol which would be used in a ``with`` statement should be + registered with :meth:`with_resource` instead. + + :param f: The function to execute on teardown. + """ + return self._exit_stack.callback(f) + + def close(self) -> None: + """Invoke all close callbacks registered with + :meth:`call_on_close`, and exit all context managers entered + with :meth:`with_resource`. + """ + self._exit_stack.close() + # In case the context is reused, create a new exit stack. + self._exit_stack = ExitStack() + + @property + def command_path(self) -> str: + """The computed command path. This is used for the ``usage`` + information on the help page. It's automatically created by + combining the info names of the chain of contexts to the root. + """ + rv = "" + if self.info_name is not None: + rv = self.info_name + if self.parent is not None: + parent_command_path = [self.parent.command_path] + + if isinstance(self.parent.command, Command): + for param in self.parent.command.get_params(self): + parent_command_path.extend(param.get_usage_pieces(self)) + + rv = f"{' '.join(parent_command_path)} {rv}" + return rv.lstrip() + + def find_root(self) -> "Context": + """Finds the outermost context.""" + node = self + while node.parent is not None: + node = node.parent + return node + + def find_object(self, object_type: t.Type[V]) -> t.Optional[V]: + """Finds the closest object of a given type.""" + node: t.Optional["Context"] = self + + while node is not None: + if isinstance(node.obj, object_type): + return node.obj + + node = node.parent + + return None + + def ensure_object(self, object_type: t.Type[V]) -> V: + """Like :meth:`find_object` but sets the innermost object to a + new instance of `object_type` if it does not exist. + """ + rv = self.find_object(object_type) + if rv is None: + self.obj = rv = object_type() + return rv + + @t.overload + def lookup_default( + self, name: str, call: "te.Literal[True]" = True + ) -> t.Optional[t.Any]: + ... + + @t.overload + def lookup_default( + self, name: str, call: "te.Literal[False]" = ... + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + ... + + def lookup_default(self, name: str, call: bool = True) -> t.Optional[t.Any]: + """Get the default for a parameter from :attr:`default_map`. + + :param name: Name of the parameter. + :param call: If the default is a callable, call it. Disable to + return the callable instead. + + .. versionchanged:: 8.0 + Added the ``call`` parameter. + """ + if self.default_map is not None: + value = self.default_map.get(name) + + if call and callable(value): + return value() + + return value + + return None + + def fail(self, message: str) -> "te.NoReturn": + """Aborts the execution of the program with a specific error + message. + + :param message: the error message to fail with. + """ + raise UsageError(message, self) + + def abort(self) -> "te.NoReturn": + """Aborts the script.""" + raise Abort() + + def exit(self, code: int = 0) -> "te.NoReturn": + """Exits the application with a given exit code.""" + raise Exit(code) + + def get_usage(self) -> str: + """Helper method to get formatted usage string for the current + context and command. + """ + return self.command.get_usage(self) + + def get_help(self) -> str: + """Helper method to get formatted help page for the current + context and command. + """ + return self.command.get_help(self) + + def _make_sub_context(self, command: "Command") -> "Context": + """Create a new context of the same type as this context, but + for a new command. + + :meta private: + """ + return type(self)(command, info_name=command.name, parent=self) + + def invoke( + __self, # noqa: B902 + __callback: t.Union["Command", t.Callable[..., t.Any]], + *args: t.Any, + **kwargs: t.Any, + ) -> t.Any: + """Invokes a command callback in exactly the way it expects. There + are two ways to invoke this method: + + 1. the first argument can be a callback and all other arguments and + keyword arguments are forwarded directly to the function. + 2. the first argument is a click command object. In that case all + arguments are forwarded as well but proper click parameters + (options and click arguments) must be keyword arguments and Click + will fill in defaults. + + Note that before Click 3.2 keyword arguments were not properly filled + in against the intention of this code and no context was created. For + more information about this change and why it was done in a bugfix + release see :ref:`upgrade-to-3.2`. + + .. versionchanged:: 8.0 + All ``kwargs`` are tracked in :attr:`params` so they will be + passed if :meth:`forward` is called at multiple levels. + """ + if isinstance(__callback, Command): + other_cmd = __callback + + if other_cmd.callback is None: + raise TypeError( + "The given command does not have a callback that can be invoked." + ) + else: + __callback = other_cmd.callback + + ctx = __self._make_sub_context(other_cmd) + + for param in other_cmd.params: + if param.name not in kwargs and param.expose_value: + kwargs[param.name] = param.type_cast_value( # type: ignore + ctx, param.get_default(ctx) + ) + + # Track all kwargs as params, so that forward() will pass + # them on in subsequent calls. + ctx.params.update(kwargs) + else: + ctx = __self + + with augment_usage_errors(__self): + with ctx: + return __callback(*args, **kwargs) + + def forward( + __self, __cmd: "Command", *args: t.Any, **kwargs: t.Any # noqa: B902 + ) -> t.Any: + """Similar to :meth:`invoke` but fills in default keyword + arguments from the current context if the other command expects + it. This cannot invoke callbacks directly, only other commands. + + .. versionchanged:: 8.0 + All ``kwargs`` are tracked in :attr:`params` so they will be + passed if ``forward`` is called at multiple levels. + """ + # Can only forward to other commands, not direct callbacks. + if not isinstance(__cmd, Command): + raise TypeError("Callback is not a command.") + + for param in __self.params: + if param not in kwargs: + kwargs[param] = __self.params[param] + + return __self.invoke(__cmd, *args, **kwargs) + + def set_parameter_source(self, name: str, source: ParameterSource) -> None: + """Set the source of a parameter. This indicates the location + from which the value of the parameter was obtained. + + :param name: The name of the parameter. + :param source: A member of :class:`~click.core.ParameterSource`. + """ + self._parameter_source[name] = source + + def get_parameter_source(self, name: str) -> t.Optional[ParameterSource]: + """Get the source of a parameter. This indicates the location + from which the value of the parameter was obtained. + + This can be useful for determining when a user specified a value + on the command line that is the same as the default value. It + will be :attr:`~click.core.ParameterSource.DEFAULT` only if the + value was actually taken from the default. + + :param name: The name of the parameter. + :rtype: ParameterSource + + .. versionchanged:: 8.0 + Returns ``None`` if the parameter was not provided from any + source. + """ + return self._parameter_source.get(name) + + +class BaseCommand: + """The base command implements the minimal API contract of commands. + Most code will never use this as it does not implement a lot of useful + functionality but it can act as the direct subclass of alternative + parsing methods that do not depend on the Click parser. + + For instance, this can be used to bridge Click and other systems like + argparse or docopt. + + Because base commands do not implement a lot of the API that other + parts of Click take for granted, they are not supported for all + operations. For instance, they cannot be used with the decorators + usually and they have no built-in callback system. + + .. versionchanged:: 2.0 + Added the `context_settings` parameter. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + """ + + #: The context class to create with :meth:`make_context`. + #: + #: .. versionadded:: 8.0 + context_class: t.Type[Context] = Context + #: the default for the :attr:`Context.allow_extra_args` flag. + allow_extra_args = False + #: the default for the :attr:`Context.allow_interspersed_args` flag. + allow_interspersed_args = True + #: the default for the :attr:`Context.ignore_unknown_options` flag. + ignore_unknown_options = False + + def __init__( + self, + name: t.Optional[str], + context_settings: t.Optional[t.Dict[str, t.Any]] = None, + ) -> None: + #: the name the command thinks it has. Upon registering a command + #: on a :class:`Group` the group will default the command name + #: with this information. You should instead use the + #: :class:`Context`\'s :attr:`~Context.info_name` attribute. + self.name = name + + if context_settings is None: + context_settings = {} + + #: an optional dictionary with defaults passed to the context. + self.context_settings: t.Dict[str, t.Any] = context_settings + + def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. This traverses the entire structure + below this command. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + :param ctx: A :class:`Context` representing this command. + + .. versionadded:: 8.0 + """ + return {"name": self.name} + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self.name}>" + + def get_usage(self, ctx: Context) -> str: + raise NotImplementedError("Base commands cannot get usage") + + def get_help(self, ctx: Context) -> str: + raise NotImplementedError("Base commands cannot get help") + + def make_context( + self, + info_name: t.Optional[str], + args: t.List[str], + parent: t.Optional[Context] = None, + **extra: t.Any, + ) -> Context: + """This function when given an info name and arguments will kick + off the parsing and create a new :class:`Context`. It does not + invoke the actual command callback though. + + To quickly customize the context class used without overriding + this method, set the :attr:`context_class` attribute. + + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it's usually + the name of the script, for commands below it it's + the name of the command. + :param args: the arguments to parse as list of strings. + :param parent: the parent context if available. + :param extra: extra keyword arguments forwarded to the context + constructor. + + .. versionchanged:: 8.0 + Added the :attr:`context_class` attribute. + """ + for key, value in self.context_settings.items(): + if key not in extra: + extra[key] = value + + ctx = self.context_class( + self, info_name=info_name, parent=parent, **extra # type: ignore + ) + + with ctx.scope(cleanup=False): + self.parse_args(ctx, args) + return ctx + + def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: + """Given a context and a list of arguments this creates the parser + and parses the arguments, then modifies the context as necessary. + This is automatically invoked by :meth:`make_context`. + """ + raise NotImplementedError("Base commands do not know how to parse arguments.") + + def invoke(self, ctx: Context) -> t.Any: + """Given a context, this invokes the command. The default + implementation is raising a not implemented error. + """ + raise NotImplementedError("Base commands are not invokable by default") + + def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: + """Return a list of completions for the incomplete value. Looks + at the names of chained multi-commands. + + Any command could be part of a chained multi-command, so sibling + commands are valid at any point during command completion. Other + command classes will return more completions. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results: t.List["CompletionItem"] = [] + + while ctx.parent is not None: + ctx = ctx.parent + + if isinstance(ctx.command, MultiCommand) and ctx.command.chain: + results.extend( + CompletionItem(name, help=command.get_short_help_str()) + for name, command in _complete_visible_commands(ctx, incomplete) + if name not in ctx.protected_args + ) + + return results + + @t.overload + def main( + self, + args: t.Optional[t.Sequence[str]] = None, + prog_name: t.Optional[str] = None, + complete_var: t.Optional[str] = None, + standalone_mode: "te.Literal[True]" = True, + **extra: t.Any, + ) -> "te.NoReturn": + ... + + @t.overload + def main( + self, + args: t.Optional[t.Sequence[str]] = None, + prog_name: t.Optional[str] = None, + complete_var: t.Optional[str] = None, + standalone_mode: bool = ..., + **extra: t.Any, + ) -> t.Any: + ... + + def main( + self, + args: t.Optional[t.Sequence[str]] = None, + prog_name: t.Optional[str] = None, + complete_var: t.Optional[str] = None, + standalone_mode: bool = True, + windows_expand_args: bool = True, + **extra: t.Any, + ) -> t.Any: + """This is the way to invoke a script with all the bells and + whistles as a command line application. This will always terminate + the application after a call. If this is not wanted, ``SystemExit`` + needs to be caught. + + This method is also available by directly calling the instance of + a :class:`Command`. + + :param args: the arguments that should be used for parsing. If not + provided, ``sys.argv[1:]`` is used. + :param prog_name: the program name that should be used. By default + the program name is constructed by taking the file + name from ``sys.argv[0]``. + :param complete_var: the environment variable that controls the + bash completion support. The default is + ``"__COMPLETE"`` with prog_name in + uppercase. + :param standalone_mode: the default behavior is to invoke the script + in standalone mode. Click will then + handle exceptions and convert them into + error messages and the function will never + return but shut down the interpreter. If + this is set to `False` they will be + propagated to the caller and the return + value of this function is the return value + of :meth:`invoke`. + :param windows_expand_args: Expand glob patterns, user dir, and + env vars in command line args on Windows. + :param extra: extra keyword arguments are forwarded to the context + constructor. See :class:`Context` for more information. + + .. versionchanged:: 8.0.1 + Added the ``windows_expand_args`` parameter to allow + disabling command line arg expansion on Windows. + + .. versionchanged:: 8.0 + When taking arguments from ``sys.argv`` on Windows, glob + patterns, user dir, and env vars are expanded. + + .. versionchanged:: 3.0 + Added the ``standalone_mode`` parameter. + """ + if args is None: + args = sys.argv[1:] + + if os.name == "nt" and windows_expand_args: + args = _expand_args(args) + else: + args = list(args) + + if prog_name is None: + prog_name = _detect_program_name() + + # Process shell completion requests and exit early. + self._main_shell_completion(extra, prog_name, complete_var) + + try: + try: + with self.make_context(prog_name, args, **extra) as ctx: + rv = self.invoke(ctx) + if not standalone_mode: + return rv + # it's not safe to `ctx.exit(rv)` here! + # note that `rv` may actually contain data like "1" which + # has obvious effects + # more subtle case: `rv=[None, None]` can come out of + # chained commands which all returned `None` -- so it's not + # even always obvious that `rv` indicates success/failure + # by its truthiness/falsiness + ctx.exit() + except (EOFError, KeyboardInterrupt): + echo(file=sys.stderr) + raise Abort() from None + except ClickException as e: + if not standalone_mode: + raise + e.show() + sys.exit(e.exit_code) + except OSError as e: + if e.errno == errno.EPIPE: + sys.stdout = t.cast(t.TextIO, PacifyFlushWrapper(sys.stdout)) + sys.stderr = t.cast(t.TextIO, PacifyFlushWrapper(sys.stderr)) + sys.exit(1) + else: + raise + except Exit as e: + if standalone_mode: + sys.exit(e.exit_code) + else: + # in non-standalone mode, return the exit code + # note that this is only reached if `self.invoke` above raises + # an Exit explicitly -- thus bypassing the check there which + # would return its result + # the results of non-standalone execution may therefore be + # somewhat ambiguous: if there are codepaths which lead to + # `ctx.exit(1)` and to `return 1`, the caller won't be able to + # tell the difference between the two + return e.exit_code + except Abort: + if not standalone_mode: + raise + echo(_("Aborted!"), file=sys.stderr) + sys.exit(1) + + def _main_shell_completion( + self, + ctx_args: t.Dict[str, t.Any], + prog_name: str, + complete_var: t.Optional[str] = None, + ) -> None: + """Check if the shell is asking for tab completion, process + that, then exit early. Called from :meth:`main` before the + program is invoked. + + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. Defaults to + ``_{PROG_NAME}_COMPLETE``. + """ + if complete_var is None: + complete_var = f"_{prog_name}_COMPLETE".replace("-", "_").upper() + + instruction = os.environ.get(complete_var) + + if not instruction: + return + + from .shell_completion import shell_complete + + rv = shell_complete(self, ctx_args, prog_name, complete_var, instruction) + sys.exit(rv) + + def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any: + """Alias for :meth:`main`.""" + return self.main(*args, **kwargs) + + +class Command(BaseCommand): + """Commands are the basic building block of command line interfaces in + Click. A basic command handles command line parsing and might dispatch + more parsing to commands nested below it. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + :param callback: the callback to invoke. This is optional. + :param params: the parameters to register with this command. This can + be either :class:`Option` or :class:`Argument` objects. + :param help: the help string to use for this command. + :param epilog: like the help string but it's printed at the end of the + help page after everything else. + :param short_help: the short help to use for this command. This is + shown on the command listing of the parent command. + :param add_help_option: by default each command registers a ``--help`` + option. This can be disabled by this parameter. + :param no_args_is_help: this controls what happens if no arguments are + provided. This option is disabled by default. + If enabled this will add ``--help`` as argument + if no arguments are passed + :param hidden: hide this command from help outputs. + + :param deprecated: issues a message indicating that + the command is deprecated. + + .. versionchanged:: 8.1 + ``help``, ``epilog``, and ``short_help`` are stored unprocessed, + all formatting is done when outputting help text, not at init, + and is done even if not using the ``@command`` decorator. + + .. versionchanged:: 8.0 + Added a ``repr`` showing the command name. + + .. versionchanged:: 7.1 + Added the ``no_args_is_help`` parameter. + + .. versionchanged:: 2.0 + Added the ``context_settings`` parameter. + """ + + def __init__( + self, + name: t.Optional[str], + context_settings: t.Optional[t.Dict[str, t.Any]] = None, + callback: t.Optional[t.Callable[..., t.Any]] = None, + params: t.Optional[t.List["Parameter"]] = None, + help: t.Optional[str] = None, + epilog: t.Optional[str] = None, + short_help: t.Optional[str] = None, + options_metavar: t.Optional[str] = "[OPTIONS]", + add_help_option: bool = True, + no_args_is_help: bool = False, + hidden: bool = False, + deprecated: bool = False, + ) -> None: + super().__init__(name, context_settings) + #: the callback to execute when the command fires. This might be + #: `None` in which case nothing happens. + self.callback = callback + #: the list of parameters for this command in the order they + #: should show up in the help page and execute. Eager parameters + #: will automatically be handled before non eager ones. + self.params: t.List["Parameter"] = params or [] + self.help = help + self.epilog = epilog + self.options_metavar = options_metavar + self.short_help = short_help + self.add_help_option = add_help_option + self.no_args_is_help = no_args_is_help + self.hidden = hidden + self.deprecated = deprecated + + def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict(ctx) + info_dict.update( + params=[param.to_info_dict() for param in self.get_params(ctx)], + help=self.help, + epilog=self.epilog, + short_help=self.short_help, + hidden=self.hidden, + deprecated=self.deprecated, + ) + return info_dict + + def get_usage(self, ctx: Context) -> str: + """Formats the usage line into a string and returns it. + + Calls :meth:`format_usage` internally. + """ + formatter = ctx.make_formatter() + self.format_usage(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_params(self, ctx: Context) -> t.List["Parameter"]: + rv = self.params + help_option = self.get_help_option(ctx) + + if help_option is not None: + rv = [*rv, help_option] + + return rv + + def format_usage(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the usage line into the formatter. + + This is a low-level method called by :meth:`get_usage`. + """ + pieces = self.collect_usage_pieces(ctx) + formatter.write_usage(ctx.command_path, " ".join(pieces)) + + def collect_usage_pieces(self, ctx: Context) -> t.List[str]: + """Returns all the pieces that go into the usage line and returns + it as a list of strings. + """ + rv = [self.options_metavar] if self.options_metavar else [] + + for param in self.get_params(ctx): + rv.extend(param.get_usage_pieces(ctx)) + + return rv + + def get_help_option_names(self, ctx: Context) -> t.List[str]: + """Returns the names for the help option.""" + all_names = set(ctx.help_option_names) + for param in self.params: + all_names.difference_update(param.opts) + all_names.difference_update(param.secondary_opts) + return list(all_names) + + def get_help_option(self, ctx: Context) -> t.Optional["Option"]: + """Returns the help option object.""" + help_options = self.get_help_option_names(ctx) + + if not help_options or not self.add_help_option: + return None + + def show_help(ctx: Context, param: "Parameter", value: str) -> None: + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + return Option( + help_options, + is_flag=True, + is_eager=True, + expose_value=False, + callback=show_help, + help=_("Show this message and exit."), + ) + + def make_parser(self, ctx: Context) -> OptionParser: + """Creates the underlying option parser for this command.""" + parser = OptionParser(ctx) + for param in self.get_params(ctx): + param.add_to_parser(parser, ctx) + return parser + + def get_help(self, ctx: Context) -> str: + """Formats the help into a string and returns it. + + Calls :meth:`format_help` internally. + """ + formatter = ctx.make_formatter() + self.format_help(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_short_help_str(self, limit: int = 45) -> str: + """Gets short help for the command or makes it by shortening the + long help string. + """ + if self.short_help: + text = inspect.cleandoc(self.short_help) + elif self.help: + text = make_default_short_help(self.help, limit) + else: + text = "" + + if self.deprecated: + text = _("(Deprecated) {text}").format(text=text) + + return text.strip() + + def format_help(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the help into the formatter if it exists. + + This is a low-level method called by :meth:`get_help`. + + This calls the following methods: + + - :meth:`format_usage` + - :meth:`format_help_text` + - :meth:`format_options` + - :meth:`format_epilog` + """ + self.format_usage(ctx, formatter) + self.format_help_text(ctx, formatter) + self.format_options(ctx, formatter) + self.format_epilog(ctx, formatter) + + def format_help_text(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the help text to the formatter if it exists.""" + text = self.help if self.help is not None else "" + + if self.deprecated: + text = _("(Deprecated) {text}").format(text=text) + + if text: + text = inspect.cleandoc(text).partition("\f")[0] + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(text) + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes all the options into the formatter if they exist.""" + opts = [] + for param in self.get_params(ctx): + rv = param.get_help_record(ctx) + if rv is not None: + opts.append(rv) + + if opts: + with formatter.section(_("Options")): + formatter.write_dl(opts) + + def format_epilog(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the epilog into the formatter if it exists.""" + if self.epilog: + epilog = inspect.cleandoc(self.epilog) + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(epilog) + + def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + parser = self.make_parser(ctx) + opts, args, param_order = parser.parse_args(args=args) + + for param in iter_params_for_processing(param_order, self.get_params(ctx)): + value, args = param.handle_parse_result(ctx, opts, args) + + if args and not ctx.allow_extra_args and not ctx.resilient_parsing: + ctx.fail( + ngettext( + "Got unexpected extra argument ({args})", + "Got unexpected extra arguments ({args})", + len(args), + ).format(args=" ".join(map(str, args))) + ) + + ctx.args = args + ctx._opt_prefixes.update(parser._opt_prefixes) + return args + + def invoke(self, ctx: Context) -> t.Any: + """Given a context, this invokes the attached callback (if it exists) + in the right way. + """ + if self.deprecated: + message = _( + "DeprecationWarning: The command {name!r} is deprecated." + ).format(name=self.name) + echo(style(message, fg="red"), err=True) + + if self.callback is not None: + return ctx.invoke(self.callback, **ctx.params) + + def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: + """Return a list of completions for the incomplete value. Looks + at the names of options and chained multi-commands. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results: t.List["CompletionItem"] = [] + + if incomplete and not incomplete[0].isalnum(): + for param in self.get_params(ctx): + if ( + not isinstance(param, Option) + or param.hidden + or ( + not param.multiple + and ctx.get_parameter_source(param.name) # type: ignore + is ParameterSource.COMMANDLINE + ) + ): + continue + + results.extend( + CompletionItem(name, help=param.help) + for name in [*param.opts, *param.secondary_opts] + if name.startswith(incomplete) + ) + + results.extend(super().shell_complete(ctx, incomplete)) + return results + + +class MultiCommand(Command): + """A multi command is the basic implementation of a command that + dispatches to subcommands. The most common version is the + :class:`Group`. + + :param invoke_without_command: this controls how the multi command itself + is invoked. By default it's only invoked + if a subcommand is provided. + :param no_args_is_help: this controls what happens if no arguments are + provided. This option is enabled by default if + `invoke_without_command` is disabled or disabled + if it's enabled. If enabled this will add + ``--help`` as argument if no arguments are + passed. + :param subcommand_metavar: the string that is used in the documentation + to indicate the subcommand place. + :param chain: if this is set to `True` chaining of multiple subcommands + is enabled. This restricts the form of commands in that + they cannot have optional arguments but it allows + multiple commands to be chained together. + :param result_callback: The result callback to attach to this multi + command. This can be set or changed later with the + :meth:`result_callback` decorator. + """ + + allow_extra_args = True + allow_interspersed_args = False + + def __init__( + self, + name: t.Optional[str] = None, + invoke_without_command: bool = False, + no_args_is_help: t.Optional[bool] = None, + subcommand_metavar: t.Optional[str] = None, + chain: bool = False, + result_callback: t.Optional[t.Callable[..., t.Any]] = None, + **attrs: t.Any, + ) -> None: + super().__init__(name, **attrs) + + if no_args_is_help is None: + no_args_is_help = not invoke_without_command + + self.no_args_is_help = no_args_is_help + self.invoke_without_command = invoke_without_command + + if subcommand_metavar is None: + if chain: + subcommand_metavar = "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..." + else: + subcommand_metavar = "COMMAND [ARGS]..." + + self.subcommand_metavar = subcommand_metavar + self.chain = chain + # The result callback that is stored. This can be set or + # overridden with the :func:`result_callback` decorator. + self._result_callback = result_callback + + if self.chain: + for param in self.params: + if isinstance(param, Argument) and not param.required: + raise RuntimeError( + "Multi commands in chain mode cannot have" + " optional arguments." + ) + + def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict(ctx) + commands = {} + + for name in self.list_commands(ctx): + command = self.get_command(ctx, name) + + if command is None: + continue + + sub_ctx = ctx._make_sub_context(command) + + with sub_ctx.scope(cleanup=False): + commands[name] = command.to_info_dict(sub_ctx) + + info_dict.update(commands=commands, chain=self.chain) + return info_dict + + def collect_usage_pieces(self, ctx: Context) -> t.List[str]: + rv = super().collect_usage_pieces(ctx) + rv.append(self.subcommand_metavar) + return rv + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + super().format_options(ctx, formatter) + self.format_commands(ctx, formatter) + + def result_callback(self, replace: bool = False) -> t.Callable[[F], F]: + """Adds a result callback to the command. By default if a + result callback is already registered this will chain them but + this can be disabled with the `replace` parameter. The result + callback is invoked with the return value of the subcommand + (or the list of return values from all subcommands if chaining + is enabled) as well as the parameters as they would be passed + to the main callback. + + Example:: + + @click.group() + @click.option('-i', '--input', default=23) + def cli(input): + return 42 + + @cli.result_callback() + def process_result(result, input): + return result + input + + :param replace: if set to `True` an already existing result + callback will be removed. + + .. versionchanged:: 8.0 + Renamed from ``resultcallback``. + + .. versionadded:: 3.0 + """ + + def decorator(f: F) -> F: + old_callback = self._result_callback + + if old_callback is None or replace: + self._result_callback = f + return f + + def function(__value, *args, **kwargs): # type: ignore + inner = old_callback(__value, *args, **kwargs) # type: ignore + return f(inner, *args, **kwargs) + + self._result_callback = rv = update_wrapper(t.cast(F, function), f) + return rv + + return decorator + + def format_commands(self, ctx: Context, formatter: HelpFormatter) -> None: + """Extra format methods for multi methods that adds all the commands + after the options. + """ + commands = [] + for subcommand in self.list_commands(ctx): + cmd = self.get_command(ctx, subcommand) + # What is this, the tool lied about a command. Ignore it + if cmd is None: + continue + if cmd.hidden: + continue + + commands.append((subcommand, cmd)) + + # allow for 3 times the default spacing + if len(commands): + limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands) + + rows = [] + for subcommand, cmd in commands: + help = cmd.get_short_help_str(limit) + rows.append((subcommand, help)) + + if rows: + with formatter.section(_("Commands")): + formatter.write_dl(rows) + + def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + rest = super().parse_args(ctx, args) + + if self.chain: + ctx.protected_args = rest + ctx.args = [] + elif rest: + ctx.protected_args, ctx.args = rest[:1], rest[1:] + + return ctx.args + + def invoke(self, ctx: Context) -> t.Any: + def _process_result(value: t.Any) -> t.Any: + if self._result_callback is not None: + value = ctx.invoke(self._result_callback, value, **ctx.params) + return value + + if not ctx.protected_args: + if self.invoke_without_command: + # No subcommand was invoked, so the result callback is + # invoked with the group return value for regular + # groups, or an empty list for chained groups. + with ctx: + rv = super().invoke(ctx) + return _process_result([] if self.chain else rv) + ctx.fail(_("Missing command.")) + + # Fetch args back out + args = [*ctx.protected_args, *ctx.args] + ctx.args = [] + ctx.protected_args = [] + + # If we're not in chain mode, we only allow the invocation of a + # single command but we also inform the current context about the + # name of the command to invoke. + if not self.chain: + # Make sure the context is entered so we do not clean up + # resources until the result processor has worked. + with ctx: + cmd_name, cmd, args = self.resolve_command(ctx, args) + assert cmd is not None + ctx.invoked_subcommand = cmd_name + super().invoke(ctx) + sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) + with sub_ctx: + return _process_result(sub_ctx.command.invoke(sub_ctx)) + + # In chain mode we create the contexts step by step, but after the + # base command has been invoked. Because at that point we do not + # know the subcommands yet, the invoked subcommand attribute is + # set to ``*`` to inform the command that subcommands are executed + # but nothing else. + with ctx: + ctx.invoked_subcommand = "*" if args else None + super().invoke(ctx) + + # Otherwise we make every single context and invoke them in a + # chain. In that case the return value to the result processor + # is the list of all invoked subcommand's results. + contexts = [] + while args: + cmd_name, cmd, args = self.resolve_command(ctx, args) + assert cmd is not None + sub_ctx = cmd.make_context( + cmd_name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + ) + contexts.append(sub_ctx) + args, sub_ctx.args = sub_ctx.args, [] + + rv = [] + for sub_ctx in contexts: + with sub_ctx: + rv.append(sub_ctx.command.invoke(sub_ctx)) + return _process_result(rv) + + def resolve_command( + self, ctx: Context, args: t.List[str] + ) -> t.Tuple[t.Optional[str], t.Optional[Command], t.List[str]]: + cmd_name = make_str(args[0]) + original_cmd_name = cmd_name + + # Get the command + cmd = self.get_command(ctx, cmd_name) + + # If we can't find the command but there is a normalization + # function available, we try with that one. + if cmd is None and ctx.token_normalize_func is not None: + cmd_name = ctx.token_normalize_func(cmd_name) + cmd = self.get_command(ctx, cmd_name) + + # If we don't find the command we want to show an error message + # to the user that it was not provided. However, there is + # something else we should do: if the first argument looks like + # an option we want to kick off parsing again for arguments to + # resolve things like --help which now should go to the main + # place. + if cmd is None and not ctx.resilient_parsing: + if split_opt(cmd_name)[0]: + self.parse_args(ctx, ctx.args) + ctx.fail(_("No such command {name!r}.").format(name=original_cmd_name)) + return cmd_name if cmd else None, cmd, args[1:] + + def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: + """Given a context and a command name, this returns a + :class:`Command` object if it exists or returns `None`. + """ + raise NotImplementedError + + def list_commands(self, ctx: Context) -> t.List[str]: + """Returns a list of subcommand names in the order they should + appear. + """ + return [] + + def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: + """Return a list of completions for the incomplete value. Looks + at the names of options, subcommands, and chained + multi-commands. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results = [ + CompletionItem(name, help=command.get_short_help_str()) + for name, command in _complete_visible_commands(ctx, incomplete) + ] + results.extend(super().shell_complete(ctx, incomplete)) + return results + + +class Group(MultiCommand): + """A group allows a command to have subcommands attached. This is + the most common way to implement nesting in Click. + + :param name: The name of the group command. + :param commands: A dict mapping names to :class:`Command` objects. + Can also be a list of :class:`Command`, which will use + :attr:`Command.name` to create the dict. + :param attrs: Other command arguments described in + :class:`MultiCommand`, :class:`Command`, and + :class:`BaseCommand`. + + .. versionchanged:: 8.0 + The ``commmands`` argument can be a list of command objects. + """ + + #: If set, this is used by the group's :meth:`command` decorator + #: as the default :class:`Command` class. This is useful to make all + #: subcommands use a custom command class. + #: + #: .. versionadded:: 8.0 + command_class: t.Optional[t.Type[Command]] = None + + #: If set, this is used by the group's :meth:`group` decorator + #: as the default :class:`Group` class. This is useful to make all + #: subgroups use a custom group class. + #: + #: If set to the special value :class:`type` (literally + #: ``group_class = type``), this group's class will be used as the + #: default class. This makes a custom group class continue to make + #: custom groups. + #: + #: .. versionadded:: 8.0 + group_class: t.Optional[t.Union[t.Type["Group"], t.Type[type]]] = None + # Literal[type] isn't valid, so use Type[type] + + def __init__( + self, + name: t.Optional[str] = None, + commands: t.Optional[t.Union[t.Dict[str, Command], t.Sequence[Command]]] = None, + **attrs: t.Any, + ) -> None: + super().__init__(name, **attrs) + + if commands is None: + commands = {} + elif isinstance(commands, abc.Sequence): + commands = {c.name: c for c in commands if c.name is not None} + + #: The registered subcommands by their exported names. + self.commands: t.Dict[str, Command] = commands + + def add_command(self, cmd: Command, name: t.Optional[str] = None) -> None: + """Registers another :class:`Command` with this group. If the name + is not provided, the name of the command is used. + """ + name = name or cmd.name + if name is None: + raise TypeError("Command has no name.") + _check_multicommand(self, name, cmd, register=True) + self.commands[name] = cmd + + @t.overload + def command(self, __func: t.Callable[..., t.Any]) -> Command: + ... + + @t.overload + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Command]: + ... + + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Union[t.Callable[[t.Callable[..., t.Any]], Command], Command]: + """A shortcut decorator for declaring and attaching a command to + the group. This takes the same arguments as :func:`command` and + immediately registers the created command with this group by + calling :meth:`add_command`. + + To customize the command class used, set the + :attr:`command_class` attribute. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.0 + Added the :attr:`command_class` attribute. + """ + from .decorators import command + + if self.command_class and kwargs.get("cls") is None: + kwargs["cls"] = self.command_class + + func: t.Optional[t.Callable] = None + + if args and callable(args[0]): + assert ( + len(args) == 1 and not kwargs + ), "Use 'command(**kwargs)(callable)' to provide arguments." + (func,) = args + args = () + + def decorator(f: t.Callable[..., t.Any]) -> Command: + cmd: Command = command(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + if func is not None: + return decorator(func) + + return decorator + + @t.overload + def group(self, __func: t.Callable[..., t.Any]) -> "Group": + ... + + @t.overload + def group( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], "Group"]: + ... + + def group( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Union[t.Callable[[t.Callable[..., t.Any]], "Group"], "Group"]: + """A shortcut decorator for declaring and attaching a group to + the group. This takes the same arguments as :func:`group` and + immediately registers the created group with this group by + calling :meth:`add_command`. + + To customize the group class used, set the :attr:`group_class` + attribute. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.0 + Added the :attr:`group_class` attribute. + """ + from .decorators import group + + func: t.Optional[t.Callable] = None + + if args and callable(args[0]): + assert ( + len(args) == 1 and not kwargs + ), "Use 'group(**kwargs)(callable)' to provide arguments." + (func,) = args + args = () + + if self.group_class is not None and kwargs.get("cls") is None: + if self.group_class is type: + kwargs["cls"] = type(self) + else: + kwargs["cls"] = self.group_class + + def decorator(f: t.Callable[..., t.Any]) -> "Group": + cmd: Group = group(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + if func is not None: + return decorator(func) + + return decorator + + def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: + return self.commands.get(cmd_name) + + def list_commands(self, ctx: Context) -> t.List[str]: + return sorted(self.commands) + + +class CommandCollection(MultiCommand): + """A command collection is a multi command that merges multiple multi + commands together into one. This is a straightforward implementation + that accepts a list of different multi commands as sources and + provides all the commands for each of them. + """ + + def __init__( + self, + name: t.Optional[str] = None, + sources: t.Optional[t.List[MultiCommand]] = None, + **attrs: t.Any, + ) -> None: + super().__init__(name, **attrs) + #: The list of registered multi commands. + self.sources: t.List[MultiCommand] = sources or [] + + def add_source(self, multi_cmd: MultiCommand) -> None: + """Adds a new multi command to the chain dispatcher.""" + self.sources.append(multi_cmd) + + def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: + for source in self.sources: + rv = source.get_command(ctx, cmd_name) + + if rv is not None: + if self.chain: + _check_multicommand(self, cmd_name, rv) + + return rv + + return None + + def list_commands(self, ctx: Context) -> t.List[str]: + rv: t.Set[str] = set() + + for source in self.sources: + rv.update(source.list_commands(ctx)) + + return sorted(rv) + + +def _check_iter(value: t.Any) -> t.Iterator[t.Any]: + """Check if the value is iterable but not a string. Raises a type + error, or return an iterator over the value. + """ + if isinstance(value, str): + raise TypeError + + return iter(value) + + +class Parameter: + r"""A parameter to a command comes in two versions: they are either + :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently + not supported by design as some of the internals for parsing are + intentionally not finalized. + + Some settings are supported by both options and arguments. + + :param param_decls: the parameter declarations for this option or + argument. This is a list of flags or argument + names. + :param type: the type that should be used. Either a :class:`ParamType` + or a Python type. The later is converted into the former + automatically if supported. + :param required: controls if this is optional or not. + :param default: the default value if omitted. This can also be a callable, + in which case it's invoked when the default is needed + without any arguments. + :param callback: A function to further process or validate the value + after type conversion. It is called as ``f(ctx, param, value)`` + and must return the value. It is called for all sources, + including prompts. + :param nargs: the number of arguments to match. If not ``1`` the return + value is a tuple instead of single value. The default for + nargs is ``1`` (except if the type is a tuple, then it's + the arity of the tuple). If ``nargs=-1``, all remaining + parameters are collected. + :param metavar: how the value is represented in the help page. + :param expose_value: if this is `True` then the value is passed onwards + to the command callback and stored on the context, + otherwise it's skipped. + :param is_eager: eager values are processed before non eager ones. This + should not be set for arguments or it will inverse the + order of processing. + :param envvar: a string or list of strings that are environment variables + that should be checked. + :param shell_complete: A function that returns custom shell + completions. Used instead of the param's type completion if + given. Takes ``ctx, param, incomplete`` and must return a list + of :class:`~click.shell_completion.CompletionItem` or a list of + strings. + + .. versionchanged:: 8.0 + ``process_value`` validates required parameters and bounded + ``nargs``, and invokes the parameter callback before returning + the value. This allows the callback to validate prompts. + ``full_process_value`` is removed. + + .. versionchanged:: 8.0 + ``autocompletion`` is renamed to ``shell_complete`` and has new + semantics described above. The old name is deprecated and will + be removed in 8.1, until then it will be wrapped to match the + new requirements. + + .. versionchanged:: 8.0 + For ``multiple=True, nargs>1``, the default must be a list of + tuples. + + .. versionchanged:: 8.0 + Setting a default is no longer required for ``nargs>1``, it will + default to ``None``. ``multiple=True`` or ``nargs=-1`` will + default to ``()``. + + .. versionchanged:: 7.1 + Empty environment variables are ignored rather than taking the + empty string value. This makes it possible for scripts to clear + variables if they can't unset them. + + .. versionchanged:: 2.0 + Changed signature for parameter callback to also be passed the + parameter. The old callback format will still work, but it will + raise a warning to give you a chance to migrate the code easier. + """ + + param_type_name = "parameter" + + def __init__( + self, + param_decls: t.Optional[t.Sequence[str]] = None, + type: t.Optional[t.Union[types.ParamType, t.Any]] = None, + required: bool = False, + default: t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]] = None, + callback: t.Optional[t.Callable[[Context, "Parameter", t.Any], t.Any]] = None, + nargs: t.Optional[int] = None, + multiple: bool = False, + metavar: t.Optional[str] = None, + expose_value: bool = True, + is_eager: bool = False, + envvar: t.Optional[t.Union[str, t.Sequence[str]]] = None, + shell_complete: t.Optional[ + t.Callable[ + [Context, "Parameter", str], + t.Union[t.List["CompletionItem"], t.List[str]], + ] + ] = None, + ) -> None: + self.name, self.opts, self.secondary_opts = self._parse_decls( + param_decls or (), expose_value + ) + self.type = types.convert_type(type, default) + + # Default nargs to what the type tells us if we have that + # information available. + if nargs is None: + if self.type.is_composite: + nargs = self.type.arity + else: + nargs = 1 + + self.required = required + self.callback = callback + self.nargs = nargs + self.multiple = multiple + self.expose_value = expose_value + self.default = default + self.is_eager = is_eager + self.metavar = metavar + self.envvar = envvar + self._custom_shell_complete = shell_complete + + if __debug__: + if self.type.is_composite and nargs != self.type.arity: + raise ValueError( + f"'nargs' must be {self.type.arity} (or None) for" + f" type {self.type!r}, but it was {nargs}." + ) + + # Skip no default or callable default. + check_default = default if not callable(default) else None + + if check_default is not None: + if multiple: + try: + # Only check the first value against nargs. + check_default = next(_check_iter(check_default), None) + except TypeError: + raise ValueError( + "'default' must be a list when 'multiple' is true." + ) from None + + # Can be None for multiple with empty default. + if nargs != 1 and check_default is not None: + try: + _check_iter(check_default) + except TypeError: + if multiple: + message = ( + "'default' must be a list of lists when 'multiple' is" + " true and 'nargs' != 1." + ) + else: + message = "'default' must be a list when 'nargs' != 1." + + raise ValueError(message) from None + + if nargs > 1 and len(check_default) != nargs: + subject = "item length" if multiple else "length" + raise ValueError( + f"'default' {subject} must match nargs={nargs}." + ) + + def to_info_dict(self) -> t.Dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + .. versionadded:: 8.0 + """ + return { + "name": self.name, + "param_type_name": self.param_type_name, + "opts": self.opts, + "secondary_opts": self.secondary_opts, + "type": self.type.to_info_dict(), + "required": self.required, + "nargs": self.nargs, + "multiple": self.multiple, + "default": self.default, + "envvar": self.envvar, + } + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self.name}>" + + def _parse_decls( + self, decls: t.Sequence[str], expose_value: bool + ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: + raise NotImplementedError() + + @property + def human_readable_name(self) -> str: + """Returns the human readable name of this parameter. This is the + same as the name for options, but the metavar for arguments. + """ + return self.name # type: ignore + + def make_metavar(self) -> str: + if self.metavar is not None: + return self.metavar + + metavar = self.type.get_metavar(self) + + if metavar is None: + metavar = self.type.name.upper() + + if self.nargs != 1: + metavar += "..." + + return metavar + + @t.overload + def get_default( + self, ctx: Context, call: "te.Literal[True]" = True + ) -> t.Optional[t.Any]: + ... + + @t.overload + def get_default( + self, ctx: Context, call: bool = ... + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + ... + + def get_default( + self, ctx: Context, call: bool = True + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + """Get the default for the parameter. Tries + :meth:`Context.lookup_default` first, then the local default. + + :param ctx: Current context. + :param call: If the default is a callable, call it. Disable to + return the callable instead. + + .. versionchanged:: 8.0.2 + Type casting is no longer performed when getting a default. + + .. versionchanged:: 8.0.1 + Type casting can fail in resilient parsing mode. Invalid + defaults will not prevent showing help text. + + .. versionchanged:: 8.0 + Looks at ``ctx.default_map`` first. + + .. versionchanged:: 8.0 + Added the ``call`` parameter. + """ + value = ctx.lookup_default(self.name, call=False) # type: ignore + + if value is None: + value = self.default + + if call and callable(value): + value = value() + + return value + + def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: + raise NotImplementedError() + + def consume_value( + self, ctx: Context, opts: t.Mapping[str, t.Any] + ) -> t.Tuple[t.Any, ParameterSource]: + value = opts.get(self.name) # type: ignore + source = ParameterSource.COMMANDLINE + + if value is None: + value = self.value_from_envvar(ctx) + source = ParameterSource.ENVIRONMENT + + if value is None: + value = ctx.lookup_default(self.name) # type: ignore + source = ParameterSource.DEFAULT_MAP + + if value is None: + value = self.get_default(ctx) + source = ParameterSource.DEFAULT + + return value, source + + def type_cast_value(self, ctx: Context, value: t.Any) -> t.Any: + """Convert and validate a value against the option's + :attr:`type`, :attr:`multiple`, and :attr:`nargs`. + """ + if value is None: + return () if self.multiple or self.nargs == -1 else None + + def check_iter(value: t.Any) -> t.Iterator: + try: + return _check_iter(value) + except TypeError: + # This should only happen when passing in args manually, + # the parser should construct an iterable when parsing + # the command line. + raise BadParameter( + _("Value must be an iterable."), ctx=ctx, param=self + ) from None + + if self.nargs == 1 or self.type.is_composite: + convert: t.Callable[[t.Any], t.Any] = partial( + self.type, param=self, ctx=ctx + ) + elif self.nargs == -1: + + def convert(value: t.Any) -> t.Tuple: + return tuple(self.type(x, self, ctx) for x in check_iter(value)) + + else: # nargs > 1 + + def convert(value: t.Any) -> t.Tuple: + value = tuple(check_iter(value)) + + if len(value) != self.nargs: + raise BadParameter( + ngettext( + "Takes {nargs} values but 1 was given.", + "Takes {nargs} values but {len} were given.", + len(value), + ).format(nargs=self.nargs, len=len(value)), + ctx=ctx, + param=self, + ) + + return tuple(self.type(x, self, ctx) for x in value) + + if self.multiple: + return tuple(convert(x) for x in check_iter(value)) + + return convert(value) + + def value_is_missing(self, value: t.Any) -> bool: + if value is None: + return True + + if (self.nargs != 1 or self.multiple) and value == (): + return True + + return False + + def process_value(self, ctx: Context, value: t.Any) -> t.Any: + value = self.type_cast_value(ctx, value) + + if self.required and self.value_is_missing(value): + raise MissingParameter(ctx=ctx, param=self) + + if self.callback is not None: + value = self.callback(ctx, self, value) + + return value + + def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]: + if self.envvar is None: + return None + + if isinstance(self.envvar, str): + rv = os.environ.get(self.envvar) + + if rv: + return rv + else: + for envvar in self.envvar: + rv = os.environ.get(envvar) + + if rv: + return rv + + return None + + def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]: + rv: t.Optional[t.Any] = self.resolve_envvar_value(ctx) + + if rv is not None and self.nargs != 1: + rv = self.type.split_envvar_value(rv) + + return rv + + def handle_parse_result( + self, ctx: Context, opts: t.Mapping[str, t.Any], args: t.List[str] + ) -> t.Tuple[t.Any, t.List[str]]: + with augment_usage_errors(ctx, param=self): + value, source = self.consume_value(ctx, opts) + ctx.set_parameter_source(self.name, source) # type: ignore + + try: + value = self.process_value(ctx, value) + except Exception: + if not ctx.resilient_parsing: + raise + + value = None + + if self.expose_value: + ctx.params[self.name] = value # type: ignore + + return value, args + + def get_help_record(self, ctx: Context) -> t.Optional[t.Tuple[str, str]]: + pass + + def get_usage_pieces(self, ctx: Context) -> t.List[str]: + return [] + + def get_error_hint(self, ctx: Context) -> str: + """Get a stringified version of the param for use in error messages to + indicate which param caused the error. + """ + hint_list = self.opts or [self.human_readable_name] + return " / ".join(f"'{x}'" for x in hint_list) + + def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: + """Return a list of completions for the incomplete value. If a + ``shell_complete`` function was given during init, it is used. + Otherwise, the :attr:`type` + :meth:`~click.types.ParamType.shell_complete` function is used. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + if self._custom_shell_complete is not None: + results = self._custom_shell_complete(ctx, self, incomplete) + + if results and isinstance(results[0], str): + from click.shell_completion import CompletionItem + + results = [CompletionItem(c) for c in results] + + return t.cast(t.List["CompletionItem"], results) + + return self.type.shell_complete(ctx, self, incomplete) + + +class Option(Parameter): + """Options are usually optional values on the command line and + have some extra features that arguments don't have. + + All other parameters are passed onwards to the parameter constructor. + + :param show_default: Show the default value for this option in its + help text. Values are not shown by default, unless + :attr:`Context.show_default` is ``True``. If this value is a + string, it shows that string in parentheses instead of the + actual value. This is particularly useful for dynamic options. + For single option boolean flags, the default remains hidden if + its value is ``False``. + :param show_envvar: Controls if an environment variable should be + shown on the help page. Normally, environment variables are not + shown. + :param prompt: If set to ``True`` or a non empty string then the + user will be prompted for input. If set to ``True`` the prompt + will be the option name capitalized. + :param confirmation_prompt: Prompt a second time to confirm the + value if it was prompted for. Can be set to a string instead of + ``True`` to customize the message. + :param prompt_required: If set to ``False``, the user will be + prompted for input only when the option was specified as a flag + without a value. + :param hide_input: If this is ``True`` then the input on the prompt + will be hidden from the user. This is useful for password input. + :param is_flag: forces this option to act as a flag. The default is + auto detection. + :param flag_value: which value should be used for this flag if it's + enabled. This is set to a boolean automatically if + the option string contains a slash to mark two options. + :param multiple: if this is set to `True` then the argument is accepted + multiple times and recorded. This is similar to ``nargs`` + in how it works but supports arbitrary number of + arguments. + :param count: this flag makes an option increment an integer. + :param allow_from_autoenv: if this is enabled then the value of this + parameter will be pulled from an environment + variable in case a prefix is defined on the + context. + :param help: the help string. + :param hidden: hide this option from help outputs. + + .. versionchanged:: 8.1.0 + Help text indentation is cleaned here instead of only in the + ``@option`` decorator. + + .. versionchanged:: 8.1.0 + The ``show_default`` parameter overrides + ``Context.show_default``. + + .. versionchanged:: 8.1.0 + The default of a single option boolean flag is not shown if the + default value is ``False``. + + .. versionchanged:: 8.0.1 + ``type`` is detected from ``flag_value`` if given. + """ + + param_type_name = "option" + + def __init__( + self, + param_decls: t.Optional[t.Sequence[str]] = None, + show_default: t.Union[bool, str, None] = None, + prompt: t.Union[bool, str] = False, + confirmation_prompt: t.Union[bool, str] = False, + prompt_required: bool = True, + hide_input: bool = False, + is_flag: t.Optional[bool] = None, + flag_value: t.Optional[t.Any] = None, + multiple: bool = False, + count: bool = False, + allow_from_autoenv: bool = True, + type: t.Optional[t.Union[types.ParamType, t.Any]] = None, + help: t.Optional[str] = None, + hidden: bool = False, + show_choices: bool = True, + show_envvar: bool = False, + **attrs: t.Any, + ) -> None: + if help: + help = inspect.cleandoc(help) + + default_is_missing = "default" not in attrs + super().__init__(param_decls, type=type, multiple=multiple, **attrs) + + if prompt is True: + if self.name is None: + raise TypeError("'name' is required with 'prompt=True'.") + + prompt_text: t.Optional[str] = self.name.replace("_", " ").capitalize() + elif prompt is False: + prompt_text = None + else: + prompt_text = prompt + + self.prompt = prompt_text + self.confirmation_prompt = confirmation_prompt + self.prompt_required = prompt_required + self.hide_input = hide_input + self.hidden = hidden + + # If prompt is enabled but not required, then the option can be + # used as a flag to indicate using prompt or flag_value. + self._flag_needs_value = self.prompt is not None and not self.prompt_required + + if is_flag is None: + if flag_value is not None: + # Implicitly a flag because flag_value was set. + is_flag = True + elif self._flag_needs_value: + # Not a flag, but when used as a flag it shows a prompt. + is_flag = False + else: + # Implicitly a flag because flag options were given. + is_flag = bool(self.secondary_opts) + elif is_flag is False and not self._flag_needs_value: + # Not a flag, and prompt is not enabled, can be used as a + # flag if flag_value is set. + self._flag_needs_value = flag_value is not None + + if is_flag and default_is_missing and not self.required: + self.default: t.Union[t.Any, t.Callable[[], t.Any]] = False + + if flag_value is None: + flag_value = not self.default + + if is_flag and type is None: + # Re-guess the type from the flag value instead of the + # default. + self.type = types.convert_type(None, flag_value) + + self.is_flag: bool = is_flag + self.is_bool_flag = is_flag and isinstance(self.type, types.BoolParamType) + self.flag_value: t.Any = flag_value + + # Counting + self.count = count + if count: + if type is None: + self.type = types.IntRange(min=0) + if default_is_missing: + self.default = 0 + + self.allow_from_autoenv = allow_from_autoenv + self.help = help + self.show_default = show_default + self.show_choices = show_choices + self.show_envvar = show_envvar + + if __debug__: + if self.nargs == -1: + raise TypeError("nargs=-1 is not supported for options.") + + if self.prompt and self.is_flag and not self.is_bool_flag: + raise TypeError("'prompt' is not valid for non-boolean flag.") + + if not self.is_bool_flag and self.secondary_opts: + raise TypeError("Secondary flag is not valid for non-boolean flag.") + + if self.is_bool_flag and self.hide_input and self.prompt is not None: + raise TypeError( + "'prompt' with 'hide_input' is not valid for boolean flag." + ) + + if self.count: + if self.multiple: + raise TypeError("'count' is not valid with 'multiple'.") + + if self.is_flag: + raise TypeError("'count' is not valid with 'is_flag'.") + + if self.multiple and self.is_flag: + raise TypeError("'multiple' is not valid with 'is_flag', use 'count'.") + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + help=self.help, + prompt=self.prompt, + is_flag=self.is_flag, + flag_value=self.flag_value, + count=self.count, + hidden=self.hidden, + ) + return info_dict + + def _parse_decls( + self, decls: t.Sequence[str], expose_value: bool + ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: + opts = [] + secondary_opts = [] + name = None + possible_names = [] + + for decl in decls: + if decl.isidentifier(): + if name is not None: + raise TypeError(f"Name '{name}' defined twice") + name = decl + else: + split_char = ";" if decl[:1] == "/" else "/" + if split_char in decl: + first, second = decl.split(split_char, 1) + first = first.rstrip() + if first: + possible_names.append(split_opt(first)) + opts.append(first) + second = second.lstrip() + if second: + secondary_opts.append(second.lstrip()) + if first == second: + raise ValueError( + f"Boolean option {decl!r} cannot use the" + " same flag for true/false." + ) + else: + possible_names.append(split_opt(decl)) + opts.append(decl) + + if name is None and possible_names: + possible_names.sort(key=lambda x: -len(x[0])) # group long options first + name = possible_names[0][1].replace("-", "_").lower() + if not name.isidentifier(): + name = None + + if name is None: + if not expose_value: + return None, opts, secondary_opts + raise TypeError("Could not determine name for option") + + if not opts and not secondary_opts: + raise TypeError( + f"No options defined but a name was passed ({name})." + " Did you mean to declare an argument instead? Did" + f" you mean to pass '--{name}'?" + ) + + return name, opts, secondary_opts + + def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: + if self.multiple: + action = "append" + elif self.count: + action = "count" + else: + action = "store" + + if self.is_flag: + action = f"{action}_const" + + if self.is_bool_flag and self.secondary_opts: + parser.add_option( + obj=self, opts=self.opts, dest=self.name, action=action, const=True + ) + parser.add_option( + obj=self, + opts=self.secondary_opts, + dest=self.name, + action=action, + const=False, + ) + else: + parser.add_option( + obj=self, + opts=self.opts, + dest=self.name, + action=action, + const=self.flag_value, + ) + else: + parser.add_option( + obj=self, + opts=self.opts, + dest=self.name, + action=action, + nargs=self.nargs, + ) + + def get_help_record(self, ctx: Context) -> t.Optional[t.Tuple[str, str]]: + if self.hidden: + return None + + any_prefix_is_slash = False + + def _write_opts(opts: t.Sequence[str]) -> str: + nonlocal any_prefix_is_slash + + rv, any_slashes = join_options(opts) + + if any_slashes: + any_prefix_is_slash = True + + if not self.is_flag and not self.count: + rv += f" {self.make_metavar()}" + + return rv + + rv = [_write_opts(self.opts)] + + if self.secondary_opts: + rv.append(_write_opts(self.secondary_opts)) + + help = self.help or "" + extra = [] + + if self.show_envvar: + envvar = self.envvar + + if envvar is None: + if ( + self.allow_from_autoenv + and ctx.auto_envvar_prefix is not None + and self.name is not None + ): + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + + if envvar is not None: + var_str = ( + envvar + if isinstance(envvar, str) + else ", ".join(str(d) for d in envvar) + ) + extra.append(_("env var: {var}").format(var=var_str)) + + # Temporarily enable resilient parsing to avoid type casting + # failing for the default. Might be possible to extend this to + # help formatting in general. + resilient = ctx.resilient_parsing + ctx.resilient_parsing = True + + try: + default_value = self.get_default(ctx, call=False) + finally: + ctx.resilient_parsing = resilient + + show_default = False + show_default_is_str = False + + if self.show_default is not None: + if isinstance(self.show_default, str): + show_default_is_str = show_default = True + else: + show_default = self.show_default + elif ctx.show_default is not None: + show_default = ctx.show_default + + if show_default_is_str or (show_default and (default_value is not None)): + if show_default_is_str: + default_string = f"({self.show_default})" + elif isinstance(default_value, (list, tuple)): + default_string = ", ".join(str(d) for d in default_value) + elif inspect.isfunction(default_value): + default_string = _("(dynamic)") + elif self.is_bool_flag and self.secondary_opts: + # For boolean flags that have distinct True/False opts, + # use the opt without prefix instead of the value. + default_string = split_opt( + (self.opts if self.default else self.secondary_opts)[0] + )[1] + elif self.is_bool_flag and not self.secondary_opts and not default_value: + default_string = "" + else: + default_string = str(default_value) + + if default_string: + extra.append(_("default: {default}").format(default=default_string)) + + if ( + isinstance(self.type, types._NumberRangeBase) + # skip count with default range type + and not (self.count and self.type.min == 0 and self.type.max is None) + ): + range_str = self.type._describe_range() + + if range_str: + extra.append(range_str) + + if self.required: + extra.append(_("required")) + + if extra: + extra_str = "; ".join(extra) + help = f"{help} [{extra_str}]" if help else f"[{extra_str}]" + + return ("; " if any_prefix_is_slash else " / ").join(rv), help + + @t.overload + def get_default( + self, ctx: Context, call: "te.Literal[True]" = True + ) -> t.Optional[t.Any]: + ... + + @t.overload + def get_default( + self, ctx: Context, call: bool = ... + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + ... + + def get_default( + self, ctx: Context, call: bool = True + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + # If we're a non boolean flag our default is more complex because + # we need to look at all flags in the same group to figure out + # if we're the default one in which case we return the flag + # value as default. + if self.is_flag and not self.is_bool_flag: + for param in ctx.command.params: + if param.name == self.name and param.default: + return param.flag_value # type: ignore + + return None + + return super().get_default(ctx, call=call) + + def prompt_for_value(self, ctx: Context) -> t.Any: + """This is an alternative flow that can be activated in the full + value processing if a value does not exist. It will prompt the + user until a valid value exists and then returns the processed + value as result. + """ + assert self.prompt is not None + + # Calculate the default before prompting anything to be stable. + default = self.get_default(ctx) + + # If this is a prompt for a flag we need to handle this + # differently. + if self.is_bool_flag: + return confirm(self.prompt, default) + + return prompt( + self.prompt, + default=default, + type=self.type, + hide_input=self.hide_input, + show_choices=self.show_choices, + confirmation_prompt=self.confirmation_prompt, + value_proc=lambda x: self.process_value(ctx, x), + ) + + def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]: + rv = super().resolve_envvar_value(ctx) + + if rv is not None: + return rv + + if ( + self.allow_from_autoenv + and ctx.auto_envvar_prefix is not None + and self.name is not None + ): + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + rv = os.environ.get(envvar) + + if rv: + return rv + + return None + + def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]: + rv: t.Optional[t.Any] = self.resolve_envvar_value(ctx) + + if rv is None: + return None + + value_depth = (self.nargs != 1) + bool(self.multiple) + + if value_depth > 0: + rv = self.type.split_envvar_value(rv) + + if self.multiple and self.nargs != 1: + rv = batch(rv, self.nargs) + + return rv + + def consume_value( + self, ctx: Context, opts: t.Mapping[str, "Parameter"] + ) -> t.Tuple[t.Any, ParameterSource]: + value, source = super().consume_value(ctx, opts) + + # The parser will emit a sentinel value if the option can be + # given as a flag without a value. This is different from None + # to distinguish from the flag not being given at all. + if value is _flag_needs_value: + if self.prompt is not None and not ctx.resilient_parsing: + value = self.prompt_for_value(ctx) + source = ParameterSource.PROMPT + else: + value = self.flag_value + source = ParameterSource.COMMANDLINE + + elif ( + self.multiple + and value is not None + and any(v is _flag_needs_value for v in value) + ): + value = [self.flag_value if v is _flag_needs_value else v for v in value] + source = ParameterSource.COMMANDLINE + + # The value wasn't set, or used the param's default, prompt if + # prompting is enabled. + elif ( + source in {None, ParameterSource.DEFAULT} + and self.prompt is not None + and (self.required or self.prompt_required) + and not ctx.resilient_parsing + ): + value = self.prompt_for_value(ctx) + source = ParameterSource.PROMPT + + return value, source + + +class Argument(Parameter): + """Arguments are positional parameters to a command. They generally + provide fewer features than options but can have infinite ``nargs`` + and are required by default. + + All parameters are passed onwards to the parameter constructor. + """ + + param_type_name = "argument" + + def __init__( + self, + param_decls: t.Sequence[str], + required: t.Optional[bool] = None, + **attrs: t.Any, + ) -> None: + if required is None: + if attrs.get("default") is not None: + required = False + else: + required = attrs.get("nargs", 1) > 0 + + if "multiple" in attrs: + raise TypeError("__init__() got an unexpected keyword argument 'multiple'.") + + super().__init__(param_decls, required=required, **attrs) + + if __debug__: + if self.default is not None and self.nargs == -1: + raise TypeError("'default' is not supported for nargs=-1.") + + @property + def human_readable_name(self) -> str: + if self.metavar is not None: + return self.metavar + return self.name.upper() # type: ignore + + def make_metavar(self) -> str: + if self.metavar is not None: + return self.metavar + var = self.type.get_metavar(self) + if not var: + var = self.name.upper() # type: ignore + if not self.required: + var = f"[{var}]" + if self.nargs != 1: + var += "..." + return var + + def _parse_decls( + self, decls: t.Sequence[str], expose_value: bool + ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: + if not decls: + if not expose_value: + return None, [], [] + raise TypeError("Could not determine name for argument") + if len(decls) == 1: + name = arg = decls[0] + name = name.replace("-", "_").lower() + else: + raise TypeError( + "Arguments take exactly one parameter declaration, got" + f" {len(decls)}." + ) + return name, [arg], [] + + def get_usage_pieces(self, ctx: Context) -> t.List[str]: + return [self.make_metavar()] + + def get_error_hint(self, ctx: Context) -> str: + return f"'{self.make_metavar()}'" + + def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: + parser.add_argument(dest=self.name, nargs=self.nargs, obj=self) diff --git a/.venv/Lib/site-packages/click/decorators.py b/.venv/Lib/site-packages/click/decorators.py new file mode 100644 index 000000000..28618dc52 --- /dev/null +++ b/.venv/Lib/site-packages/click/decorators.py @@ -0,0 +1,497 @@ +import inspect +import types +import typing as t +from functools import update_wrapper +from gettext import gettext as _ + +from .core import Argument +from .core import Command +from .core import Context +from .core import Group +from .core import Option +from .core import Parameter +from .globals import get_current_context +from .utils import echo + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) +FC = t.TypeVar("FC", bound=t.Union[t.Callable[..., t.Any], Command]) + + +def pass_context(f: F) -> F: + """Marks a callback as wanting to receive the current context + object as first argument. + """ + + def new_func(*args, **kwargs): # type: ignore + return f(get_current_context(), *args, **kwargs) + + return update_wrapper(t.cast(F, new_func), f) + + +def pass_obj(f: F) -> F: + """Similar to :func:`pass_context`, but only pass the object on the + context onwards (:attr:`Context.obj`). This is useful if that object + represents the state of a nested system. + """ + + def new_func(*args, **kwargs): # type: ignore + return f(get_current_context().obj, *args, **kwargs) + + return update_wrapper(t.cast(F, new_func), f) + + +def make_pass_decorator( + object_type: t.Type, ensure: bool = False +) -> "t.Callable[[F], F]": + """Given an object type this creates a decorator that will work + similar to :func:`pass_obj` but instead of passing the object of the + current context, it will find the innermost context of type + :func:`object_type`. + + This generates a decorator that works roughly like this:: + + from functools import update_wrapper + + def decorator(f): + @pass_context + def new_func(ctx, *args, **kwargs): + obj = ctx.find_object(object_type) + return ctx.invoke(f, obj, *args, **kwargs) + return update_wrapper(new_func, f) + return decorator + + :param object_type: the type of the object to pass. + :param ensure: if set to `True`, a new object will be created and + remembered on the context if it's not there yet. + """ + + def decorator(f: F) -> F: + def new_func(*args, **kwargs): # type: ignore + ctx = get_current_context() + + if ensure: + obj = ctx.ensure_object(object_type) + else: + obj = ctx.find_object(object_type) + + if obj is None: + raise RuntimeError( + "Managed to invoke callback without a context" + f" object of type {object_type.__name__!r}" + " existing." + ) + + return ctx.invoke(f, obj, *args, **kwargs) + + return update_wrapper(t.cast(F, new_func), f) + + return decorator + + +def pass_meta_key( + key: str, *, doc_description: t.Optional[str] = None +) -> "t.Callable[[F], F]": + """Create a decorator that passes a key from + :attr:`click.Context.meta` as the first argument to the decorated + function. + + :param key: Key in ``Context.meta`` to pass. + :param doc_description: Description of the object being passed, + inserted into the decorator's docstring. Defaults to "the 'key' + key from Context.meta". + + .. versionadded:: 8.0 + """ + + def decorator(f: F) -> F: + def new_func(*args, **kwargs): # type: ignore + ctx = get_current_context() + obj = ctx.meta[key] + return ctx.invoke(f, obj, *args, **kwargs) + + return update_wrapper(t.cast(F, new_func), f) + + if doc_description is None: + doc_description = f"the {key!r} key from :attr:`click.Context.meta`" + + decorator.__doc__ = ( + f"Decorator that passes {doc_description} as the first argument" + " to the decorated function." + ) + return decorator + + +CmdType = t.TypeVar("CmdType", bound=Command) + + +@t.overload +def command( + __func: t.Callable[..., t.Any], +) -> Command: + ... + + +@t.overload +def command( + name: t.Optional[str] = None, + **attrs: t.Any, +) -> t.Callable[..., Command]: + ... + + +@t.overload +def command( + name: t.Optional[str] = None, + cls: t.Type[CmdType] = ..., + **attrs: t.Any, +) -> t.Callable[..., CmdType]: + ... + + +def command( + name: t.Union[str, t.Callable[..., t.Any], None] = None, + cls: t.Optional[t.Type[Command]] = None, + **attrs: t.Any, +) -> t.Union[Command, t.Callable[..., Command]]: + r"""Creates a new :class:`Command` and uses the decorated function as + callback. This will also automatically attach all decorated + :func:`option`\s and :func:`argument`\s as parameters to the command. + + The name of the command defaults to the name of the function with + underscores replaced by dashes. If you want to change that, you can + pass the intended name as the first argument. + + All keyword arguments are forwarded to the underlying command class. + For the ``params`` argument, any decorated params are appended to + the end of the list. + + Once decorated the function turns into a :class:`Command` instance + that can be invoked as a command line utility or be attached to a + command :class:`Group`. + + :param name: the name of the command. This defaults to the function + name with underscores replaced by dashes. + :param cls: the command class to instantiate. This defaults to + :class:`Command`. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.1 + The ``params`` argument can be used. Decorated params are + appended to the end of the list. + """ + + func: t.Optional[t.Callable[..., t.Any]] = None + + if callable(name): + func = name + name = None + assert cls is None, "Use 'command(cls=cls)(callable)' to specify a class." + assert not attrs, "Use 'command(**kwargs)(callable)' to provide arguments." + + if cls is None: + cls = Command + + def decorator(f: t.Callable[..., t.Any]) -> Command: + if isinstance(f, Command): + raise TypeError("Attempted to convert a callback into a command twice.") + + attr_params = attrs.pop("params", None) + params = attr_params if attr_params is not None else [] + + try: + decorator_params = f.__click_params__ # type: ignore + except AttributeError: + pass + else: + del f.__click_params__ # type: ignore + params.extend(reversed(decorator_params)) + + if attrs.get("help") is None: + attrs["help"] = f.__doc__ + + cmd = cls( # type: ignore[misc] + name=name or f.__name__.lower().replace("_", "-"), # type: ignore[arg-type] + callback=f, + params=params, + **attrs, + ) + cmd.__doc__ = f.__doc__ + return cmd + + if func is not None: + return decorator(func) + + return decorator + + +@t.overload +def group( + __func: t.Callable[..., t.Any], +) -> Group: + ... + + +@t.overload +def group( + name: t.Optional[str] = None, + **attrs: t.Any, +) -> t.Callable[[F], Group]: + ... + + +def group( + name: t.Union[str, t.Callable[..., t.Any], None] = None, **attrs: t.Any +) -> t.Union[Group, t.Callable[[F], Group]]: + """Creates a new :class:`Group` with a function as callback. This + works otherwise the same as :func:`command` just that the `cls` + parameter is set to :class:`Group`. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + """ + if attrs.get("cls") is None: + attrs["cls"] = Group + + if callable(name): + grp: t.Callable[[F], Group] = t.cast(Group, command(**attrs)) + return grp(name) + + return t.cast(Group, command(name, **attrs)) + + +def _param_memo(f: FC, param: Parameter) -> None: + if isinstance(f, Command): + f.params.append(param) + else: + if not hasattr(f, "__click_params__"): + f.__click_params__ = [] # type: ignore + + f.__click_params__.append(param) # type: ignore + + +def argument(*param_decls: str, **attrs: t.Any) -> t.Callable[[FC], FC]: + """Attaches an argument to the command. All positional arguments are + passed as parameter declarations to :class:`Argument`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Argument` instance manually + and attaching it to the :attr:`Command.params` list. + + :param cls: the argument class to instantiate. This defaults to + :class:`Argument`. + """ + + def decorator(f: FC) -> FC: + ArgumentClass = attrs.pop("cls", None) or Argument + _param_memo(f, ArgumentClass(param_decls, **attrs)) + return f + + return decorator + + +def option(*param_decls: str, **attrs: t.Any) -> t.Callable[[FC], FC]: + """Attaches an option to the command. All positional arguments are + passed as parameter declarations to :class:`Option`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Option` instance manually + and attaching it to the :attr:`Command.params` list. + + :param cls: the option class to instantiate. This defaults to + :class:`Option`. + """ + + def decorator(f: FC) -> FC: + # Issue 926, copy attrs, so pre-defined options can re-use the same cls= + option_attrs = attrs.copy() + OptionClass = option_attrs.pop("cls", None) or Option + _param_memo(f, OptionClass(param_decls, **option_attrs)) + return f + + return decorator + + +def confirmation_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--yes`` option which shows a prompt before continuing if + not passed. If the prompt is declined, the program will exit. + + :param param_decls: One or more option names. Defaults to the single + value ``"--yes"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value: + ctx.abort() + + if not param_decls: + param_decls = ("--yes",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("callback", callback) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("prompt", "Do you want to continue?") + kwargs.setdefault("help", "Confirm the action without prompting.") + return option(*param_decls, **kwargs) + + +def password_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--password`` option which prompts for a password, hiding + input and asking to enter the value again for confirmation. + + :param param_decls: One or more option names. Defaults to the single + value ``"--password"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + if not param_decls: + param_decls = ("--password",) + + kwargs.setdefault("prompt", True) + kwargs.setdefault("confirmation_prompt", True) + kwargs.setdefault("hide_input", True) + return option(*param_decls, **kwargs) + + +def version_option( + version: t.Optional[str] = None, + *param_decls: str, + package_name: t.Optional[str] = None, + prog_name: t.Optional[str] = None, + message: t.Optional[str] = None, + **kwargs: t.Any, +) -> t.Callable[[FC], FC]: + """Add a ``--version`` option which immediately prints the version + number and exits the program. + + If ``version`` is not provided, Click will try to detect it using + :func:`importlib.metadata.version` to get the version for the + ``package_name``. On Python < 3.8, the ``importlib_metadata`` + backport must be installed. + + If ``package_name`` is not provided, Click will try to detect it by + inspecting the stack frames. This will be used to detect the + version, so it must match the name of the installed package. + + :param version: The version number to show. If not provided, Click + will try to detect it. + :param param_decls: One or more option names. Defaults to the single + value ``"--version"``. + :param package_name: The package name to detect the version from. If + not provided, Click will try to detect it. + :param prog_name: The name of the CLI to show in the message. If not + provided, it will be detected from the command. + :param message: The message to show. The values ``%(prog)s``, + ``%(package)s``, and ``%(version)s`` are available. Defaults to + ``"%(prog)s, version %(version)s"``. + :param kwargs: Extra arguments are passed to :func:`option`. + :raise RuntimeError: ``version`` could not be detected. + + .. versionchanged:: 8.0 + Add the ``package_name`` parameter, and the ``%(package)s`` + value for messages. + + .. versionchanged:: 8.0 + Use :mod:`importlib.metadata` instead of ``pkg_resources``. The + version is detected based on the package name, not the entry + point name. The Python package name must match the installed + package name, or be passed with ``package_name=``. + """ + if message is None: + message = _("%(prog)s, version %(version)s") + + if version is None and package_name is None: + frame = inspect.currentframe() + f_back = frame.f_back if frame is not None else None + f_globals = f_back.f_globals if f_back is not None else None + # break reference cycle + # https://docs.python.org/3/library/inspect.html#the-interpreter-stack + del frame + + if f_globals is not None: + package_name = f_globals.get("__name__") + + if package_name == "__main__": + package_name = f_globals.get("__package__") + + if package_name: + package_name = package_name.partition(".")[0] + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value or ctx.resilient_parsing: + return + + nonlocal prog_name + nonlocal version + + if prog_name is None: + prog_name = ctx.find_root().info_name + + if version is None and package_name is not None: + metadata: t.Optional[types.ModuleType] + + try: + from importlib import metadata # type: ignore + except ImportError: + # Python < 3.8 + import importlib_metadata as metadata # type: ignore + + try: + version = metadata.version(package_name) # type: ignore + except metadata.PackageNotFoundError: # type: ignore + raise RuntimeError( + f"{package_name!r} is not installed. Try passing" + " 'package_name' instead." + ) from None + + if version is None: + raise RuntimeError( + f"Could not determine the version for {package_name!r} automatically." + ) + + echo( + t.cast(str, message) + % {"prog": prog_name, "package": package_name, "version": version}, + color=ctx.color, + ) + ctx.exit() + + if not param_decls: + param_decls = ("--version",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show the version and exit.")) + kwargs["callback"] = callback + return option(*param_decls, **kwargs) + + +def help_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--help`` option which immediately prints the help page + and exits the program. + + This is usually unnecessary, as the ``--help`` option is added to + each command automatically unless ``add_help_option=False`` is + passed. + + :param param_decls: One or more option names. Defaults to the single + value ``"--help"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value or ctx.resilient_parsing: + return + + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + if not param_decls: + param_decls = ("--help",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show this message and exit.")) + kwargs["callback"] = callback + return option(*param_decls, **kwargs) diff --git a/.venv/Lib/site-packages/click/exceptions.py b/.venv/Lib/site-packages/click/exceptions.py new file mode 100644 index 000000000..9e20b3eb5 --- /dev/null +++ b/.venv/Lib/site-packages/click/exceptions.py @@ -0,0 +1,287 @@ +import os +import typing as t +from gettext import gettext as _ +from gettext import ngettext + +from ._compat import get_text_stderr +from .utils import echo + +if t.TYPE_CHECKING: + from .core import Context + from .core import Parameter + + +def _join_param_hints( + param_hint: t.Optional[t.Union[t.Sequence[str], str]] +) -> t.Optional[str]: + if param_hint is not None and not isinstance(param_hint, str): + return " / ".join(repr(x) for x in param_hint) + + return param_hint + + +class ClickException(Exception): + """An exception that Click can handle and show to the user.""" + + #: The exit code for this exception. + exit_code = 1 + + def __init__(self, message: str) -> None: + super().__init__(message) + self.message = message + + def format_message(self) -> str: + return self.message + + def __str__(self) -> str: + return self.message + + def show(self, file: t.Optional[t.IO] = None) -> None: + if file is None: + file = get_text_stderr() + + echo(_("Error: {message}").format(message=self.format_message()), file=file) + + +class UsageError(ClickException): + """An internal exception that signals a usage error. This typically + aborts any further handling. + + :param message: the error message to display. + :param ctx: optionally the context that caused this error. Click will + fill in the context automatically in some situations. + """ + + exit_code = 2 + + def __init__(self, message: str, ctx: t.Optional["Context"] = None) -> None: + super().__init__(message) + self.ctx = ctx + self.cmd = self.ctx.command if self.ctx else None + + def show(self, file: t.Optional[t.IO] = None) -> None: + if file is None: + file = get_text_stderr() + color = None + hint = "" + if ( + self.ctx is not None + and self.ctx.command.get_help_option(self.ctx) is not None + ): + hint = _("Try '{command} {option}' for help.").format( + command=self.ctx.command_path, option=self.ctx.help_option_names[0] + ) + hint = f"{hint}\n" + if self.ctx is not None: + color = self.ctx.color + echo(f"{self.ctx.get_usage()}\n{hint}", file=file, color=color) + echo( + _("Error: {message}").format(message=self.format_message()), + file=file, + color=color, + ) + + +class BadParameter(UsageError): + """An exception that formats out a standardized error message for a + bad parameter. This is useful when thrown from a callback or type as + Click will attach contextual information to it (for instance, which + parameter it is). + + .. versionadded:: 2.0 + + :param param: the parameter object that caused this error. This can + be left out, and Click will attach this info itself + if possible. + :param param_hint: a string that shows up as parameter name. This + can be used as alternative to `param` in cases + where custom validation should happen. If it is + a string it's used as such, if it's a list then + each item is quoted and separated. + """ + + def __init__( + self, + message: str, + ctx: t.Optional["Context"] = None, + param: t.Optional["Parameter"] = None, + param_hint: t.Optional[str] = None, + ) -> None: + super().__init__(message, ctx) + self.param = param + self.param_hint = param_hint + + def format_message(self) -> str: + if self.param_hint is not None: + param_hint = self.param_hint + elif self.param is not None: + param_hint = self.param.get_error_hint(self.ctx) # type: ignore + else: + return _("Invalid value: {message}").format(message=self.message) + + return _("Invalid value for {param_hint}: {message}").format( + param_hint=_join_param_hints(param_hint), message=self.message + ) + + +class MissingParameter(BadParameter): + """Raised if click required an option or argument but it was not + provided when invoking the script. + + .. versionadded:: 4.0 + + :param param_type: a string that indicates the type of the parameter. + The default is to inherit the parameter type from + the given `param`. Valid values are ``'parameter'``, + ``'option'`` or ``'argument'``. + """ + + def __init__( + self, + message: t.Optional[str] = None, + ctx: t.Optional["Context"] = None, + param: t.Optional["Parameter"] = None, + param_hint: t.Optional[str] = None, + param_type: t.Optional[str] = None, + ) -> None: + super().__init__(message or "", ctx, param, param_hint) + self.param_type = param_type + + def format_message(self) -> str: + if self.param_hint is not None: + param_hint: t.Optional[str] = self.param_hint + elif self.param is not None: + param_hint = self.param.get_error_hint(self.ctx) # type: ignore + else: + param_hint = None + + param_hint = _join_param_hints(param_hint) + param_hint = f" {param_hint}" if param_hint else "" + + param_type = self.param_type + if param_type is None and self.param is not None: + param_type = self.param.param_type_name + + msg = self.message + if self.param is not None: + msg_extra = self.param.type.get_missing_message(self.param) + if msg_extra: + if msg: + msg += f". {msg_extra}" + else: + msg = msg_extra + + msg = f" {msg}" if msg else "" + + # Translate param_type for known types. + if param_type == "argument": + missing = _("Missing argument") + elif param_type == "option": + missing = _("Missing option") + elif param_type == "parameter": + missing = _("Missing parameter") + else: + missing = _("Missing {param_type}").format(param_type=param_type) + + return f"{missing}{param_hint}.{msg}" + + def __str__(self) -> str: + if not self.message: + param_name = self.param.name if self.param else None + return _("Missing parameter: {param_name}").format(param_name=param_name) + else: + return self.message + + +class NoSuchOption(UsageError): + """Raised if click attempted to handle an option that does not + exist. + + .. versionadded:: 4.0 + """ + + def __init__( + self, + option_name: str, + message: t.Optional[str] = None, + possibilities: t.Optional[t.Sequence[str]] = None, + ctx: t.Optional["Context"] = None, + ) -> None: + if message is None: + message = _("No such option: {name}").format(name=option_name) + + super().__init__(message, ctx) + self.option_name = option_name + self.possibilities = possibilities + + def format_message(self) -> str: + if not self.possibilities: + return self.message + + possibility_str = ", ".join(sorted(self.possibilities)) + suggest = ngettext( + "Did you mean {possibility}?", + "(Possible options: {possibilities})", + len(self.possibilities), + ).format(possibility=possibility_str, possibilities=possibility_str) + return f"{self.message} {suggest}" + + +class BadOptionUsage(UsageError): + """Raised if an option is generally supplied but the use of the option + was incorrect. This is for instance raised if the number of arguments + for an option is not correct. + + .. versionadded:: 4.0 + + :param option_name: the name of the option being used incorrectly. + """ + + def __init__( + self, option_name: str, message: str, ctx: t.Optional["Context"] = None + ) -> None: + super().__init__(message, ctx) + self.option_name = option_name + + +class BadArgumentUsage(UsageError): + """Raised if an argument is generally supplied but the use of the argument + was incorrect. This is for instance raised if the number of values + for an argument is not correct. + + .. versionadded:: 6.0 + """ + + +class FileError(ClickException): + """Raised if a file cannot be opened.""" + + def __init__(self, filename: str, hint: t.Optional[str] = None) -> None: + if hint is None: + hint = _("unknown error") + + super().__init__(hint) + self.ui_filename = os.fsdecode(filename) + self.filename = filename + + def format_message(self) -> str: + return _("Could not open file {filename!r}: {message}").format( + filename=self.ui_filename, message=self.message + ) + + +class Abort(RuntimeError): + """An internal signalling exception that signals Click to abort.""" + + +class Exit(RuntimeError): + """An exception that indicates that the application should exit with some + status code. + + :param code: the status code to exit with. + """ + + __slots__ = ("exit_code",) + + def __init__(self, code: int = 0) -> None: + self.exit_code = code diff --git a/.venv/Lib/site-packages/click/formatting.py b/.venv/Lib/site-packages/click/formatting.py new file mode 100644 index 000000000..ddd2a2f82 --- /dev/null +++ b/.venv/Lib/site-packages/click/formatting.py @@ -0,0 +1,301 @@ +import typing as t +from contextlib import contextmanager +from gettext import gettext as _ + +from ._compat import term_len +from .parser import split_opt + +# Can force a width. This is used by the test system +FORCED_WIDTH: t.Optional[int] = None + + +def measure_table(rows: t.Iterable[t.Tuple[str, str]]) -> t.Tuple[int, ...]: + widths: t.Dict[int, int] = {} + + for row in rows: + for idx, col in enumerate(row): + widths[idx] = max(widths.get(idx, 0), term_len(col)) + + return tuple(y for x, y in sorted(widths.items())) + + +def iter_rows( + rows: t.Iterable[t.Tuple[str, str]], col_count: int +) -> t.Iterator[t.Tuple[str, ...]]: + for row in rows: + yield row + ("",) * (col_count - len(row)) + + +def wrap_text( + text: str, + width: int = 78, + initial_indent: str = "", + subsequent_indent: str = "", + preserve_paragraphs: bool = False, +) -> str: + """A helper function that intelligently wraps text. By default, it + assumes that it operates on a single paragraph of text but if the + `preserve_paragraphs` parameter is provided it will intelligently + handle paragraphs (defined by two empty lines). + + If paragraphs are handled, a paragraph can be prefixed with an empty + line containing the ``\\b`` character (``\\x08``) to indicate that + no rewrapping should happen in that block. + + :param text: the text that should be rewrapped. + :param width: the maximum width for the text. + :param initial_indent: the initial indent that should be placed on the + first line as a string. + :param subsequent_indent: the indent string that should be placed on + each consecutive line. + :param preserve_paragraphs: if this flag is set then the wrapping will + intelligently handle paragraphs. + """ + from ._textwrap import TextWrapper + + text = text.expandtabs() + wrapper = TextWrapper( + width, + initial_indent=initial_indent, + subsequent_indent=subsequent_indent, + replace_whitespace=False, + ) + if not preserve_paragraphs: + return wrapper.fill(text) + + p: t.List[t.Tuple[int, bool, str]] = [] + buf: t.List[str] = [] + indent = None + + def _flush_par() -> None: + if not buf: + return + if buf[0].strip() == "\b": + p.append((indent or 0, True, "\n".join(buf[1:]))) + else: + p.append((indent or 0, False, " ".join(buf))) + del buf[:] + + for line in text.splitlines(): + if not line: + _flush_par() + indent = None + else: + if indent is None: + orig_len = term_len(line) + line = line.lstrip() + indent = orig_len - term_len(line) + buf.append(line) + _flush_par() + + rv = [] + for indent, raw, text in p: + with wrapper.extra_indent(" " * indent): + if raw: + rv.append(wrapper.indent_only(text)) + else: + rv.append(wrapper.fill(text)) + + return "\n\n".join(rv) + + +class HelpFormatter: + """This class helps with formatting text-based help pages. It's + usually just needed for very special internal cases, but it's also + exposed so that developers can write their own fancy outputs. + + At present, it always writes into memory. + + :param indent_increment: the additional increment for each level. + :param width: the width for the text. This defaults to the terminal + width clamped to a maximum of 78. + """ + + def __init__( + self, + indent_increment: int = 2, + width: t.Optional[int] = None, + max_width: t.Optional[int] = None, + ) -> None: + import shutil + + self.indent_increment = indent_increment + if max_width is None: + max_width = 80 + if width is None: + width = FORCED_WIDTH + if width is None: + width = max(min(shutil.get_terminal_size().columns, max_width) - 2, 50) + self.width = width + self.current_indent = 0 + self.buffer: t.List[str] = [] + + def write(self, string: str) -> None: + """Writes a unicode string into the internal buffer.""" + self.buffer.append(string) + + def indent(self) -> None: + """Increases the indentation.""" + self.current_indent += self.indent_increment + + def dedent(self) -> None: + """Decreases the indentation.""" + self.current_indent -= self.indent_increment + + def write_usage( + self, prog: str, args: str = "", prefix: t.Optional[str] = None + ) -> None: + """Writes a usage line into the buffer. + + :param prog: the program name. + :param args: whitespace separated list of arguments. + :param prefix: The prefix for the first line. Defaults to + ``"Usage: "``. + """ + if prefix is None: + prefix = f"{_('Usage:')} " + + usage_prefix = f"{prefix:>{self.current_indent}}{prog} " + text_width = self.width - self.current_indent + + if text_width >= (term_len(usage_prefix) + 20): + # The arguments will fit to the right of the prefix. + indent = " " * term_len(usage_prefix) + self.write( + wrap_text( + args, + text_width, + initial_indent=usage_prefix, + subsequent_indent=indent, + ) + ) + else: + # The prefix is too long, put the arguments on the next line. + self.write(usage_prefix) + self.write("\n") + indent = " " * (max(self.current_indent, term_len(prefix)) + 4) + self.write( + wrap_text( + args, text_width, initial_indent=indent, subsequent_indent=indent + ) + ) + + self.write("\n") + + def write_heading(self, heading: str) -> None: + """Writes a heading into the buffer.""" + self.write(f"{'':>{self.current_indent}}{heading}:\n") + + def write_paragraph(self) -> None: + """Writes a paragraph into the buffer.""" + if self.buffer: + self.write("\n") + + def write_text(self, text: str) -> None: + """Writes re-indented text into the buffer. This rewraps and + preserves paragraphs. + """ + indent = " " * self.current_indent + self.write( + wrap_text( + text, + self.width, + initial_indent=indent, + subsequent_indent=indent, + preserve_paragraphs=True, + ) + ) + self.write("\n") + + def write_dl( + self, + rows: t.Sequence[t.Tuple[str, str]], + col_max: int = 30, + col_spacing: int = 2, + ) -> None: + """Writes a definition list into the buffer. This is how options + and commands are usually formatted. + + :param rows: a list of two item tuples for the terms and values. + :param col_max: the maximum width of the first column. + :param col_spacing: the number of spaces between the first and + second column. + """ + rows = list(rows) + widths = measure_table(rows) + if len(widths) != 2: + raise TypeError("Expected two columns for definition list") + + first_col = min(widths[0], col_max) + col_spacing + + for first, second in iter_rows(rows, len(widths)): + self.write(f"{'':>{self.current_indent}}{first}") + if not second: + self.write("\n") + continue + if term_len(first) <= first_col - col_spacing: + self.write(" " * (first_col - term_len(first))) + else: + self.write("\n") + self.write(" " * (first_col + self.current_indent)) + + text_width = max(self.width - first_col - 2, 10) + wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True) + lines = wrapped_text.splitlines() + + if lines: + self.write(f"{lines[0]}\n") + + for line in lines[1:]: + self.write(f"{'':>{first_col + self.current_indent}}{line}\n") + else: + self.write("\n") + + @contextmanager + def section(self, name: str) -> t.Iterator[None]: + """Helpful context manager that writes a paragraph, a heading, + and the indents. + + :param name: the section name that is written as heading. + """ + self.write_paragraph() + self.write_heading(name) + self.indent() + try: + yield + finally: + self.dedent() + + @contextmanager + def indentation(self) -> t.Iterator[None]: + """A context manager that increases the indentation.""" + self.indent() + try: + yield + finally: + self.dedent() + + def getvalue(self) -> str: + """Returns the buffer contents.""" + return "".join(self.buffer) + + +def join_options(options: t.Sequence[str]) -> t.Tuple[str, bool]: + """Given a list of option strings this joins them in the most appropriate + way and returns them in the form ``(formatted_string, + any_prefix_is_slash)`` where the second item in the tuple is a flag that + indicates if any of the option prefixes was a slash. + """ + rv = [] + any_prefix_is_slash = False + + for opt in options: + prefix = split_opt(opt)[0] + + if prefix == "/": + any_prefix_is_slash = True + + rv.append((len(prefix), opt)) + + rv.sort(key=lambda x: x[0]) + return ", ".join(x[1] for x in rv), any_prefix_is_slash diff --git a/.venv/Lib/site-packages/click/globals.py b/.venv/Lib/site-packages/click/globals.py new file mode 100644 index 000000000..480058f10 --- /dev/null +++ b/.venv/Lib/site-packages/click/globals.py @@ -0,0 +1,68 @@ +import typing as t +from threading import local + +if t.TYPE_CHECKING: + import typing_extensions as te + from .core import Context + +_local = local() + + +@t.overload +def get_current_context(silent: "te.Literal[False]" = False) -> "Context": + ... + + +@t.overload +def get_current_context(silent: bool = ...) -> t.Optional["Context"]: + ... + + +def get_current_context(silent: bool = False) -> t.Optional["Context"]: + """Returns the current click context. This can be used as a way to + access the current context object from anywhere. This is a more implicit + alternative to the :func:`pass_context` decorator. This function is + primarily useful for helpers such as :func:`echo` which might be + interested in changing its behavior based on the current context. + + To push the current context, :meth:`Context.scope` can be used. + + .. versionadded:: 5.0 + + :param silent: if set to `True` the return value is `None` if no context + is available. The default behavior is to raise a + :exc:`RuntimeError`. + """ + try: + return t.cast("Context", _local.stack[-1]) + except (AttributeError, IndexError) as e: + if not silent: + raise RuntimeError("There is no active click context.") from e + + return None + + +def push_context(ctx: "Context") -> None: + """Pushes a new context to the current stack.""" + _local.__dict__.setdefault("stack", []).append(ctx) + + +def pop_context() -> None: + """Removes the top level from the stack.""" + _local.stack.pop() + + +def resolve_color_default(color: t.Optional[bool] = None) -> t.Optional[bool]: + """Internal helper to get the default value of the color flag. If a + value is passed it's returned unchanged, otherwise it's looked up from + the current context. + """ + if color is not None: + return color + + ctx = get_current_context(silent=True) + + if ctx is not None: + return ctx.color + + return None diff --git a/.venv/Lib/site-packages/click/parser.py b/.venv/Lib/site-packages/click/parser.py new file mode 100644 index 000000000..2d5a2ed7b --- /dev/null +++ b/.venv/Lib/site-packages/click/parser.py @@ -0,0 +1,529 @@ +""" +This module started out as largely a copy paste from the stdlib's +optparse module with the features removed that we do not need from +optparse because we implement them in Click on a higher level (for +instance type handling, help formatting and a lot more). + +The plan is to remove more and more from here over time. + +The reason this is a different module and not optparse from the stdlib +is that there are differences in 2.x and 3.x about the error messages +generated and optparse in the stdlib uses gettext for no good reason +and might cause us issues. + +Click uses parts of optparse written by Gregory P. Ward and maintained +by the Python Software Foundation. This is limited to code in parser.py. + +Copyright 2001-2006 Gregory P. Ward. All rights reserved. +Copyright 2002-2006 Python Software Foundation. All rights reserved. +""" +# This code uses parts of optparse written by Gregory P. Ward and +# maintained by the Python Software Foundation. +# Copyright 2001-2006 Gregory P. Ward +# Copyright 2002-2006 Python Software Foundation +import typing as t +from collections import deque +from gettext import gettext as _ +from gettext import ngettext + +from .exceptions import BadArgumentUsage +from .exceptions import BadOptionUsage +from .exceptions import NoSuchOption +from .exceptions import UsageError + +if t.TYPE_CHECKING: + import typing_extensions as te + from .core import Argument as CoreArgument + from .core import Context + from .core import Option as CoreOption + from .core import Parameter as CoreParameter + +V = t.TypeVar("V") + +# Sentinel value that indicates an option was passed as a flag without a +# value but is not a flag option. Option.consume_value uses this to +# prompt or use the flag_value. +_flag_needs_value = object() + + +def _unpack_args( + args: t.Sequence[str], nargs_spec: t.Sequence[int] +) -> t.Tuple[t.Sequence[t.Union[str, t.Sequence[t.Optional[str]], None]], t.List[str]]: + """Given an iterable of arguments and an iterable of nargs specifications, + it returns a tuple with all the unpacked arguments at the first index + and all remaining arguments as the second. + + The nargs specification is the number of arguments that should be consumed + or `-1` to indicate that this position should eat up all the remainders. + + Missing items are filled with `None`. + """ + args = deque(args) + nargs_spec = deque(nargs_spec) + rv: t.List[t.Union[str, t.Tuple[t.Optional[str], ...], None]] = [] + spos: t.Optional[int] = None + + def _fetch(c: "te.Deque[V]") -> t.Optional[V]: + try: + if spos is None: + return c.popleft() + else: + return c.pop() + except IndexError: + return None + + while nargs_spec: + nargs = _fetch(nargs_spec) + + if nargs is None: + continue + + if nargs == 1: + rv.append(_fetch(args)) + elif nargs > 1: + x = [_fetch(args) for _ in range(nargs)] + + # If we're reversed, we're pulling in the arguments in reverse, + # so we need to turn them around. + if spos is not None: + x.reverse() + + rv.append(tuple(x)) + elif nargs < 0: + if spos is not None: + raise TypeError("Cannot have two nargs < 0") + + spos = len(rv) + rv.append(None) + + # spos is the position of the wildcard (star). If it's not `None`, + # we fill it with the remainder. + if spos is not None: + rv[spos] = tuple(args) + args = [] + rv[spos + 1 :] = reversed(rv[spos + 1 :]) + + return tuple(rv), list(args) + + +def split_opt(opt: str) -> t.Tuple[str, str]: + first = opt[:1] + if first.isalnum(): + return "", opt + if opt[1:2] == first: + return opt[:2], opt[2:] + return first, opt[1:] + + +def normalize_opt(opt: str, ctx: t.Optional["Context"]) -> str: + if ctx is None or ctx.token_normalize_func is None: + return opt + prefix, opt = split_opt(opt) + return f"{prefix}{ctx.token_normalize_func(opt)}" + + +def split_arg_string(string: str) -> t.List[str]: + """Split an argument string as with :func:`shlex.split`, but don't + fail if the string is incomplete. Ignores a missing closing quote or + incomplete escape sequence and uses the partial token as-is. + + .. code-block:: python + + split_arg_string("example 'my file") + ["example", "my file"] + + split_arg_string("example my\\") + ["example", "my"] + + :param string: String to split. + """ + import shlex + + lex = shlex.shlex(string, posix=True) + lex.whitespace_split = True + lex.commenters = "" + out = [] + + try: + for token in lex: + out.append(token) + except ValueError: + # Raised when end-of-string is reached in an invalid state. Use + # the partial token as-is. The quote or escape character is in + # lex.state, not lex.token. + out.append(lex.token) + + return out + + +class Option: + def __init__( + self, + obj: "CoreOption", + opts: t.Sequence[str], + dest: t.Optional[str], + action: t.Optional[str] = None, + nargs: int = 1, + const: t.Optional[t.Any] = None, + ): + self._short_opts = [] + self._long_opts = [] + self.prefixes = set() + + for opt in opts: + prefix, value = split_opt(opt) + if not prefix: + raise ValueError(f"Invalid start character for option ({opt})") + self.prefixes.add(prefix[0]) + if len(prefix) == 1 and len(value) == 1: + self._short_opts.append(opt) + else: + self._long_opts.append(opt) + self.prefixes.add(prefix) + + if action is None: + action = "store" + + self.dest = dest + self.action = action + self.nargs = nargs + self.const = const + self.obj = obj + + @property + def takes_value(self) -> bool: + return self.action in ("store", "append") + + def process(self, value: str, state: "ParsingState") -> None: + if self.action == "store": + state.opts[self.dest] = value # type: ignore + elif self.action == "store_const": + state.opts[self.dest] = self.const # type: ignore + elif self.action == "append": + state.opts.setdefault(self.dest, []).append(value) # type: ignore + elif self.action == "append_const": + state.opts.setdefault(self.dest, []).append(self.const) # type: ignore + elif self.action == "count": + state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 # type: ignore + else: + raise ValueError(f"unknown action '{self.action}'") + state.order.append(self.obj) + + +class Argument: + def __init__(self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1): + self.dest = dest + self.nargs = nargs + self.obj = obj + + def process( + self, + value: t.Union[t.Optional[str], t.Sequence[t.Optional[str]]], + state: "ParsingState", + ) -> None: + if self.nargs > 1: + assert value is not None + holes = sum(1 for x in value if x is None) + if holes == len(value): + value = None + elif holes != 0: + raise BadArgumentUsage( + _("Argument {name!r} takes {nargs} values.").format( + name=self.dest, nargs=self.nargs + ) + ) + + if self.nargs == -1 and self.obj.envvar is not None and value == (): + # Replace empty tuple with None so that a value from the + # environment may be tried. + value = None + + state.opts[self.dest] = value # type: ignore + state.order.append(self.obj) + + +class ParsingState: + def __init__(self, rargs: t.List[str]) -> None: + self.opts: t.Dict[str, t.Any] = {} + self.largs: t.List[str] = [] + self.rargs = rargs + self.order: t.List["CoreParameter"] = [] + + +class OptionParser: + """The option parser is an internal class that is ultimately used to + parse options and arguments. It's modelled after optparse and brings + a similar but vastly simplified API. It should generally not be used + directly as the high level Click classes wrap it for you. + + It's not nearly as extensible as optparse or argparse as it does not + implement features that are implemented on a higher level (such as + types or defaults). + + :param ctx: optionally the :class:`~click.Context` where this parser + should go with. + """ + + def __init__(self, ctx: t.Optional["Context"] = None) -> None: + #: The :class:`~click.Context` for this parser. This might be + #: `None` for some advanced use cases. + self.ctx = ctx + #: This controls how the parser deals with interspersed arguments. + #: If this is set to `False`, the parser will stop on the first + #: non-option. Click uses this to implement nested subcommands + #: safely. + self.allow_interspersed_args = True + #: This tells the parser how to deal with unknown options. By + #: default it will error out (which is sensible), but there is a + #: second mode where it will ignore it and continue processing + #: after shifting all the unknown options into the resulting args. + self.ignore_unknown_options = False + + if ctx is not None: + self.allow_interspersed_args = ctx.allow_interspersed_args + self.ignore_unknown_options = ctx.ignore_unknown_options + + self._short_opt: t.Dict[str, Option] = {} + self._long_opt: t.Dict[str, Option] = {} + self._opt_prefixes = {"-", "--"} + self._args: t.List[Argument] = [] + + def add_option( + self, + obj: "CoreOption", + opts: t.Sequence[str], + dest: t.Optional[str], + action: t.Optional[str] = None, + nargs: int = 1, + const: t.Optional[t.Any] = None, + ) -> None: + """Adds a new option named `dest` to the parser. The destination + is not inferred (unlike with optparse) and needs to be explicitly + provided. Action can be any of ``store``, ``store_const``, + ``append``, ``append_const`` or ``count``. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + opts = [normalize_opt(opt, self.ctx) for opt in opts] + option = Option(obj, opts, dest, action=action, nargs=nargs, const=const) + self._opt_prefixes.update(option.prefixes) + for opt in option._short_opts: + self._short_opt[opt] = option + for opt in option._long_opts: + self._long_opt[opt] = option + + def add_argument( + self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1 + ) -> None: + """Adds a positional argument named `dest` to the parser. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + self._args.append(Argument(obj, dest=dest, nargs=nargs)) + + def parse_args( + self, args: t.List[str] + ) -> t.Tuple[t.Dict[str, t.Any], t.List[str], t.List["CoreParameter"]]: + """Parses positional arguments and returns ``(values, args, order)`` + for the parsed options and arguments as well as the leftover + arguments if there are any. The order is a list of objects as they + appear on the command line. If arguments appear multiple times they + will be memorized multiple times as well. + """ + state = ParsingState(args) + try: + self._process_args_for_options(state) + self._process_args_for_args(state) + except UsageError: + if self.ctx is None or not self.ctx.resilient_parsing: + raise + return state.opts, state.largs, state.order + + def _process_args_for_args(self, state: ParsingState) -> None: + pargs, args = _unpack_args( + state.largs + state.rargs, [x.nargs for x in self._args] + ) + + for idx, arg in enumerate(self._args): + arg.process(pargs[idx], state) + + state.largs = args + state.rargs = [] + + def _process_args_for_options(self, state: ParsingState) -> None: + while state.rargs: + arg = state.rargs.pop(0) + arglen = len(arg) + # Double dashes always handled explicitly regardless of what + # prefixes are valid. + if arg == "--": + return + elif arg[:1] in self._opt_prefixes and arglen > 1: + self._process_opts(arg, state) + elif self.allow_interspersed_args: + state.largs.append(arg) + else: + state.rargs.insert(0, arg) + return + + # Say this is the original argument list: + # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] + # ^ + # (we are about to process arg(i)). + # + # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of + # [arg0, ..., arg(i-1)] (any options and their arguments will have + # been removed from largs). + # + # The while loop will usually consume 1 or more arguments per pass. + # If it consumes 1 (eg. arg is an option that takes no arguments), + # then after _process_arg() is done the situation is: + # + # largs = subset of [arg0, ..., arg(i)] + # rargs = [arg(i+1), ..., arg(N-1)] + # + # If allow_interspersed_args is false, largs will always be + # *empty* -- still a subset of [arg0, ..., arg(i-1)], but + # not a very interesting subset! + + def _match_long_opt( + self, opt: str, explicit_value: t.Optional[str], state: ParsingState + ) -> None: + if opt not in self._long_opt: + from difflib import get_close_matches + + possibilities = get_close_matches(opt, self._long_opt) + raise NoSuchOption(opt, possibilities=possibilities, ctx=self.ctx) + + option = self._long_opt[opt] + if option.takes_value: + # At this point it's safe to modify rargs by injecting the + # explicit value, because no exception is raised in this + # branch. This means that the inserted value will be fully + # consumed. + if explicit_value is not None: + state.rargs.insert(0, explicit_value) + + value = self._get_value_from_state(opt, option, state) + + elif explicit_value is not None: + raise BadOptionUsage( + opt, _("Option {name!r} does not take a value.").format(name=opt) + ) + + else: + value = None + + option.process(value, state) + + def _match_short_opt(self, arg: str, state: ParsingState) -> None: + stop = False + i = 1 + prefix = arg[0] + unknown_options = [] + + for ch in arg[1:]: + opt = normalize_opt(f"{prefix}{ch}", self.ctx) + option = self._short_opt.get(opt) + i += 1 + + if not option: + if self.ignore_unknown_options: + unknown_options.append(ch) + continue + raise NoSuchOption(opt, ctx=self.ctx) + if option.takes_value: + # Any characters left in arg? Pretend they're the + # next arg, and stop consuming characters of arg. + if i < len(arg): + state.rargs.insert(0, arg[i:]) + stop = True + + value = self._get_value_from_state(opt, option, state) + + else: + value = None + + option.process(value, state) + + if stop: + break + + # If we got any unknown options we re-combinate the string of the + # remaining options and re-attach the prefix, then report that + # to the state as new larg. This way there is basic combinatorics + # that can be achieved while still ignoring unknown arguments. + if self.ignore_unknown_options and unknown_options: + state.largs.append(f"{prefix}{''.join(unknown_options)}") + + def _get_value_from_state( + self, option_name: str, option: Option, state: ParsingState + ) -> t.Any: + nargs = option.nargs + + if len(state.rargs) < nargs: + if option.obj._flag_needs_value: + # Option allows omitting the value. + value = _flag_needs_value + else: + raise BadOptionUsage( + option_name, + ngettext( + "Option {name!r} requires an argument.", + "Option {name!r} requires {nargs} arguments.", + nargs, + ).format(name=option_name, nargs=nargs), + ) + elif nargs == 1: + next_rarg = state.rargs[0] + + if ( + option.obj._flag_needs_value + and isinstance(next_rarg, str) + and next_rarg[:1] in self._opt_prefixes + and len(next_rarg) > 1 + ): + # The next arg looks like the start of an option, don't + # use it as the value if omitting the value is allowed. + value = _flag_needs_value + else: + value = state.rargs.pop(0) + else: + value = tuple(state.rargs[:nargs]) + del state.rargs[:nargs] + + return value + + def _process_opts(self, arg: str, state: ParsingState) -> None: + explicit_value = None + # Long option handling happens in two parts. The first part is + # supporting explicitly attached values. In any case, we will try + # to long match the option first. + if "=" in arg: + long_opt, explicit_value = arg.split("=", 1) + else: + long_opt = arg + norm_long_opt = normalize_opt(long_opt, self.ctx) + + # At this point we will match the (assumed) long option through + # the long option matching code. Note that this allows options + # like "-foo" to be matched as long options. + try: + self._match_long_opt(norm_long_opt, explicit_value, state) + except NoSuchOption: + # At this point the long option matching failed, and we need + # to try with short options. However there is a special rule + # which says, that if we have a two character options prefix + # (applies to "--foo" for instance), we do not dispatch to the + # short option code and will instead raise the no option + # error. + if arg[:2] not in self._opt_prefixes: + self._match_short_opt(arg, state) + return + + if not self.ignore_unknown_options: + raise + + state.largs.append(arg) diff --git a/.venv/Lib/site-packages/click/py.typed b/.venv/Lib/site-packages/click/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/.venv/Lib/site-packages/click/shell_completion.py b/.venv/Lib/site-packages/click/shell_completion.py new file mode 100644 index 000000000..c17a8e643 --- /dev/null +++ b/.venv/Lib/site-packages/click/shell_completion.py @@ -0,0 +1,580 @@ +import os +import re +import typing as t +from gettext import gettext as _ + +from .core import Argument +from .core import BaseCommand +from .core import Context +from .core import MultiCommand +from .core import Option +from .core import Parameter +from .core import ParameterSource +from .parser import split_arg_string +from .utils import echo + + +def shell_complete( + cli: BaseCommand, + ctx_args: t.Dict[str, t.Any], + prog_name: str, + complete_var: str, + instruction: str, +) -> int: + """Perform shell completion for the given CLI program. + + :param cli: Command being called. + :param ctx_args: Extra arguments to pass to + ``cli.make_context``. + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. + :param instruction: Value of ``complete_var`` with the completion + instruction and shell, in the form ``instruction_shell``. + :return: Status code to exit with. + """ + shell, _, instruction = instruction.partition("_") + comp_cls = get_completion_class(shell) + + if comp_cls is None: + return 1 + + comp = comp_cls(cli, ctx_args, prog_name, complete_var) + + if instruction == "source": + echo(comp.source()) + return 0 + + if instruction == "complete": + echo(comp.complete()) + return 0 + + return 1 + + +class CompletionItem: + """Represents a completion value and metadata about the value. The + default metadata is ``type`` to indicate special shell handling, + and ``help`` if a shell supports showing a help string next to the + value. + + Arbitrary parameters can be passed when creating the object, and + accessed using ``item.attr``. If an attribute wasn't passed, + accessing it returns ``None``. + + :param value: The completion suggestion. + :param type: Tells the shell script to provide special completion + support for the type. Click uses ``"dir"`` and ``"file"``. + :param help: String shown next to the value if supported. + :param kwargs: Arbitrary metadata. The built-in implementations + don't use this, but custom type completions paired with custom + shell support could use it. + """ + + __slots__ = ("value", "type", "help", "_info") + + def __init__( + self, + value: t.Any, + type: str = "plain", + help: t.Optional[str] = None, + **kwargs: t.Any, + ) -> None: + self.value = value + self.type = type + self.help = help + self._info = kwargs + + def __getattr__(self, name: str) -> t.Any: + return self._info.get(name) + + +# Only Bash >= 4.4 has the nosort option. +_SOURCE_BASH = """\ +%(complete_func)s() { + local IFS=$'\\n' + local response + + response=$(env COMP_WORDS="${COMP_WORDS[*]}" COMP_CWORD=$COMP_CWORD \ +%(complete_var)s=bash_complete $1) + + for completion in $response; do + IFS=',' read type value <<< "$completion" + + if [[ $type == 'dir' ]]; then + COMPREPLY=() + compopt -o dirnames + elif [[ $type == 'file' ]]; then + COMPREPLY=() + compopt -o default + elif [[ $type == 'plain' ]]; then + COMPREPLY+=($value) + fi + done + + return 0 +} + +%(complete_func)s_setup() { + complete -o nosort -F %(complete_func)s %(prog_name)s +} + +%(complete_func)s_setup; +""" + +_SOURCE_ZSH = """\ +#compdef %(prog_name)s + +%(complete_func)s() { + local -a completions + local -a completions_with_descriptions + local -a response + (( ! $+commands[%(prog_name)s] )) && return 1 + + response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) \ +%(complete_var)s=zsh_complete %(prog_name)s)}") + + for type key descr in ${response}; do + if [[ "$type" == "plain" ]]; then + if [[ "$descr" == "_" ]]; then + completions+=("$key") + else + completions_with_descriptions+=("$key":"$descr") + fi + elif [[ "$type" == "dir" ]]; then + _path_files -/ + elif [[ "$type" == "file" ]]; then + _path_files -f + fi + done + + if [ -n "$completions_with_descriptions" ]; then + _describe -V unsorted completions_with_descriptions -U + fi + + if [ -n "$completions" ]; then + compadd -U -V unsorted -a completions + fi +} + +compdef %(complete_func)s %(prog_name)s; +""" + +_SOURCE_FISH = """\ +function %(complete_func)s; + set -l response; + + for value in (env %(complete_var)s=fish_complete COMP_WORDS=(commandline -cp) \ +COMP_CWORD=(commandline -t) %(prog_name)s); + set response $response $value; + end; + + for completion in $response; + set -l metadata (string split "," $completion); + + if test $metadata[1] = "dir"; + __fish_complete_directories $metadata[2]; + else if test $metadata[1] = "file"; + __fish_complete_path $metadata[2]; + else if test $metadata[1] = "plain"; + echo $metadata[2]; + end; + end; +end; + +complete --no-files --command %(prog_name)s --arguments \ +"(%(complete_func)s)"; +""" + + +class ShellComplete: + """Base class for providing shell completion support. A subclass for + a given shell will override attributes and methods to implement the + completion instructions (``source`` and ``complete``). + + :param cli: Command being called. + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. + + .. versionadded:: 8.0 + """ + + name: t.ClassVar[str] + """Name to register the shell as with :func:`add_completion_class`. + This is used in completion instructions (``{name}_source`` and + ``{name}_complete``). + """ + + source_template: t.ClassVar[str] + """Completion script template formatted by :meth:`source`. This must + be provided by subclasses. + """ + + def __init__( + self, + cli: BaseCommand, + ctx_args: t.Dict[str, t.Any], + prog_name: str, + complete_var: str, + ) -> None: + self.cli = cli + self.ctx_args = ctx_args + self.prog_name = prog_name + self.complete_var = complete_var + + @property + def func_name(self) -> str: + """The name of the shell function defined by the completion + script. + """ + safe_name = re.sub(r"\W*", "", self.prog_name.replace("-", "_"), re.ASCII) + return f"_{safe_name}_completion" + + def source_vars(self) -> t.Dict[str, t.Any]: + """Vars for formatting :attr:`source_template`. + + By default this provides ``complete_func``, ``complete_var``, + and ``prog_name``. + """ + return { + "complete_func": self.func_name, + "complete_var": self.complete_var, + "prog_name": self.prog_name, + } + + def source(self) -> str: + """Produce the shell script that defines the completion + function. By default this ``%``-style formats + :attr:`source_template` with the dict returned by + :meth:`source_vars`. + """ + return self.source_template % self.source_vars() + + def get_completion_args(self) -> t.Tuple[t.List[str], str]: + """Use the env vars defined by the shell script to return a + tuple of ``args, incomplete``. This must be implemented by + subclasses. + """ + raise NotImplementedError + + def get_completions( + self, args: t.List[str], incomplete: str + ) -> t.List[CompletionItem]: + """Determine the context and last complete command or parameter + from the complete args. Call that object's ``shell_complete`` + method to get the completions for the incomplete value. + + :param args: List of complete args before the incomplete value. + :param incomplete: Value being completed. May be empty. + """ + ctx = _resolve_context(self.cli, self.ctx_args, self.prog_name, args) + obj, incomplete = _resolve_incomplete(ctx, args, incomplete) + return obj.shell_complete(ctx, incomplete) + + def format_completion(self, item: CompletionItem) -> str: + """Format a completion item into the form recognized by the + shell script. This must be implemented by subclasses. + + :param item: Completion item to format. + """ + raise NotImplementedError + + def complete(self) -> str: + """Produce the completion data to send back to the shell. + + By default this calls :meth:`get_completion_args`, gets the + completions, then calls :meth:`format_completion` for each + completion. + """ + args, incomplete = self.get_completion_args() + completions = self.get_completions(args, incomplete) + out = [self.format_completion(item) for item in completions] + return "\n".join(out) + + +class BashComplete(ShellComplete): + """Shell completion for Bash.""" + + name = "bash" + source_template = _SOURCE_BASH + + def _check_version(self) -> None: + import subprocess + + output = subprocess.run( + ["bash", "-c", "echo ${BASH_VERSION}"], stdout=subprocess.PIPE + ) + match = re.search(r"^(\d+)\.(\d+)\.\d+", output.stdout.decode()) + + if match is not None: + major, minor = match.groups() + + if major < "4" or major == "4" and minor < "4": + raise RuntimeError( + _( + "Shell completion is not supported for Bash" + " versions older than 4.4." + ) + ) + else: + raise RuntimeError( + _("Couldn't detect Bash version, shell completion is not supported.") + ) + + def source(self) -> str: + self._check_version() + return super().source() + + def get_completion_args(self) -> t.Tuple[t.List[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + return f"{item.type},{item.value}" + + +class ZshComplete(ShellComplete): + """Shell completion for Zsh.""" + + name = "zsh" + source_template = _SOURCE_ZSH + + def get_completion_args(self) -> t.Tuple[t.List[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + return f"{item.type}\n{item.value}\n{item.help if item.help else '_'}" + + +class FishComplete(ShellComplete): + """Shell completion for Fish.""" + + name = "fish" + source_template = _SOURCE_FISH + + def get_completion_args(self) -> t.Tuple[t.List[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + incomplete = os.environ["COMP_CWORD"] + args = cwords[1:] + + # Fish stores the partial word in both COMP_WORDS and + # COMP_CWORD, remove it from complete args. + if incomplete and args and args[-1] == incomplete: + args.pop() + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + if item.help: + return f"{item.type},{item.value}\t{item.help}" + + return f"{item.type},{item.value}" + + +_available_shells: t.Dict[str, t.Type[ShellComplete]] = { + "bash": BashComplete, + "fish": FishComplete, + "zsh": ZshComplete, +} + + +def add_completion_class( + cls: t.Type[ShellComplete], name: t.Optional[str] = None +) -> None: + """Register a :class:`ShellComplete` subclass under the given name. + The name will be provided by the completion instruction environment + variable during completion. + + :param cls: The completion class that will handle completion for the + shell. + :param name: Name to register the class under. Defaults to the + class's ``name`` attribute. + """ + if name is None: + name = cls.name + + _available_shells[name] = cls + + +def get_completion_class(shell: str) -> t.Optional[t.Type[ShellComplete]]: + """Look up a registered :class:`ShellComplete` subclass by the name + provided by the completion instruction environment variable. If the + name isn't registered, returns ``None``. + + :param shell: Name the class is registered under. + """ + return _available_shells.get(shell) + + +def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool: + """Determine if the given parameter is an argument that can still + accept values. + + :param ctx: Invocation context for the command represented by the + parsed complete args. + :param param: Argument object being checked. + """ + if not isinstance(param, Argument): + return False + + assert param.name is not None + value = ctx.params[param.name] + return ( + param.nargs == -1 + or ctx.get_parameter_source(param.name) is not ParameterSource.COMMANDLINE + or ( + param.nargs > 1 + and isinstance(value, (tuple, list)) + and len(value) < param.nargs + ) + ) + + +def _start_of_option(ctx: Context, value: str) -> bool: + """Check if the value looks like the start of an option.""" + if not value: + return False + + c = value[0] + return c in ctx._opt_prefixes + + +def _is_incomplete_option(ctx: Context, args: t.List[str], param: Parameter) -> bool: + """Determine if the given parameter is an option that needs a value. + + :param args: List of complete args before the incomplete value. + :param param: Option object being checked. + """ + if not isinstance(param, Option): + return False + + if param.is_flag or param.count: + return False + + last_option = None + + for index, arg in enumerate(reversed(args)): + if index + 1 > param.nargs: + break + + if _start_of_option(ctx, arg): + last_option = arg + + return last_option is not None and last_option in param.opts + + +def _resolve_context( + cli: BaseCommand, ctx_args: t.Dict[str, t.Any], prog_name: str, args: t.List[str] +) -> Context: + """Produce the context hierarchy starting with the command and + traversing the complete arguments. This only follows the commands, + it doesn't trigger input prompts or callbacks. + + :param cli: Command being called. + :param prog_name: Name of the executable in the shell. + :param args: List of complete args before the incomplete value. + """ + ctx_args["resilient_parsing"] = True + ctx = cli.make_context(prog_name, args.copy(), **ctx_args) + args = ctx.protected_args + ctx.args + + while args: + command = ctx.command + + if isinstance(command, MultiCommand): + if not command.chain: + name, cmd, args = command.resolve_command(ctx, args) + + if cmd is None: + return ctx + + ctx = cmd.make_context(name, args, parent=ctx, resilient_parsing=True) + args = ctx.protected_args + ctx.args + else: + while args: + name, cmd, args = command.resolve_command(ctx, args) + + if cmd is None: + return ctx + + sub_ctx = cmd.make_context( + name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + resilient_parsing=True, + ) + args = sub_ctx.args + + ctx = sub_ctx + args = [*sub_ctx.protected_args, *sub_ctx.args] + else: + break + + return ctx + + +def _resolve_incomplete( + ctx: Context, args: t.List[str], incomplete: str +) -> t.Tuple[t.Union[BaseCommand, Parameter], str]: + """Find the Click object that will handle the completion of the + incomplete value. Return the object and the incomplete value. + + :param ctx: Invocation context for the command represented by + the parsed complete args. + :param args: List of complete args before the incomplete value. + :param incomplete: Value being completed. May be empty. + """ + # Different shells treat an "=" between a long option name and + # value differently. Might keep the value joined, return the "=" + # as a separate item, or return the split name and value. Always + # split and discard the "=" to make completion easier. + if incomplete == "=": + incomplete = "" + elif "=" in incomplete and _start_of_option(ctx, incomplete): + name, _, incomplete = incomplete.partition("=") + args.append(name) + + # The "--" marker tells Click to stop treating values as options + # even if they start with the option character. If it hasn't been + # given and the incomplete arg looks like an option, the current + # command will provide option name completions. + if "--" not in args and _start_of_option(ctx, incomplete): + return ctx.command, incomplete + + params = ctx.command.get_params(ctx) + + # If the last complete arg is an option name with an incomplete + # value, the option will provide value completions. + for param in params: + if _is_incomplete_option(ctx, args, param): + return param, incomplete + + # It's not an option name or value. The first argument without a + # parsed value will provide value completions. + for param in params: + if _is_incomplete_argument(ctx, param): + return param, incomplete + + # There were no unparsed arguments, the command may be a group that + # will provide command name completions. + return ctx.command, incomplete diff --git a/.venv/Lib/site-packages/click/termui.py b/.venv/Lib/site-packages/click/termui.py new file mode 100644 index 000000000..bfb2f5ae6 --- /dev/null +++ b/.venv/Lib/site-packages/click/termui.py @@ -0,0 +1,787 @@ +import inspect +import io +import itertools +import os +import sys +import typing as t +from gettext import gettext as _ + +from ._compat import isatty +from ._compat import strip_ansi +from ._compat import WIN +from .exceptions import Abort +from .exceptions import UsageError +from .globals import resolve_color_default +from .types import Choice +from .types import convert_type +from .types import ParamType +from .utils import echo +from .utils import LazyFile + +if t.TYPE_CHECKING: + from ._termui_impl import ProgressBar + +V = t.TypeVar("V") + +# The prompt functions to use. The doc tools currently override these +# functions to customize how they work. +visible_prompt_func: t.Callable[[str], str] = input + +_ansi_colors = { + "black": 30, + "red": 31, + "green": 32, + "yellow": 33, + "blue": 34, + "magenta": 35, + "cyan": 36, + "white": 37, + "reset": 39, + "bright_black": 90, + "bright_red": 91, + "bright_green": 92, + "bright_yellow": 93, + "bright_blue": 94, + "bright_magenta": 95, + "bright_cyan": 96, + "bright_white": 97, +} +_ansi_reset_all = "\033[0m" + + +def hidden_prompt_func(prompt: str) -> str: + import getpass + + return getpass.getpass(prompt) + + +def _build_prompt( + text: str, + suffix: str, + show_default: bool = False, + default: t.Optional[t.Any] = None, + show_choices: bool = True, + type: t.Optional[ParamType] = None, +) -> str: + prompt = text + if type is not None and show_choices and isinstance(type, Choice): + prompt += f" ({', '.join(map(str, type.choices))})" + if default is not None and show_default: + prompt = f"{prompt} [{_format_default(default)}]" + return f"{prompt}{suffix}" + + +def _format_default(default: t.Any) -> t.Any: + if isinstance(default, (io.IOBase, LazyFile)) and hasattr(default, "name"): + return default.name # type: ignore + + return default + + +def prompt( + text: str, + default: t.Optional[t.Any] = None, + hide_input: bool = False, + confirmation_prompt: t.Union[bool, str] = False, + type: t.Optional[t.Union[ParamType, t.Any]] = None, + value_proc: t.Optional[t.Callable[[str], t.Any]] = None, + prompt_suffix: str = ": ", + show_default: bool = True, + err: bool = False, + show_choices: bool = True, +) -> t.Any: + """Prompts a user for input. This is a convenience function that can + be used to prompt a user for input later. + + If the user aborts the input by sending an interrupt signal, this + function will catch it and raise a :exc:`Abort` exception. + + :param text: the text to show for the prompt. + :param default: the default value to use if no input happens. If this + is not given it will prompt until it's aborted. + :param hide_input: if this is set to true then the input value will + be hidden. + :param confirmation_prompt: Prompt a second time to confirm the + value. Can be set to a string instead of ``True`` to customize + the message. + :param type: the type to use to check the value against. + :param value_proc: if this parameter is provided it's a function that + is invoked instead of the type conversion to + convert a value. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + :param show_choices: Show or hide choices if the passed type is a Choice. + For example if type is a Choice of either day or week, + show_choices is true and text is "Group by" then the + prompt will be "Group by (day, week): ". + + .. versionadded:: 8.0 + ``confirmation_prompt`` can be a custom string. + + .. versionadded:: 7.0 + Added the ``show_choices`` parameter. + + .. versionadded:: 6.0 + Added unicode support for cmd.exe on Windows. + + .. versionadded:: 4.0 + Added the `err` parameter. + + """ + + def prompt_func(text: str) -> str: + f = hidden_prompt_func if hide_input else visible_prompt_func + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(text.rstrip(" "), nl=False, err=err) + # Echo a space to stdout to work around an issue where + # readline causes backspace to clear the whole line. + return f(" ") + except (KeyboardInterrupt, EOFError): + # getpass doesn't print a newline if the user aborts input with ^C. + # Allegedly this behavior is inherited from getpass(3). + # A doc bug has been filed at https://bugs.python.org/issue24711 + if hide_input: + echo(None, err=err) + raise Abort() from None + + if value_proc is None: + value_proc = convert_type(type, default) + + prompt = _build_prompt( + text, prompt_suffix, show_default, default, show_choices, type + ) + + if confirmation_prompt: + if confirmation_prompt is True: + confirmation_prompt = _("Repeat for confirmation") + + confirmation_prompt = _build_prompt(confirmation_prompt, prompt_suffix) + + while True: + while True: + value = prompt_func(prompt) + if value: + break + elif default is not None: + value = default + break + try: + result = value_proc(value) + except UsageError as e: + if hide_input: + echo(_("Error: The value you entered was invalid."), err=err) + else: + echo(_("Error: {e.message}").format(e=e), err=err) # noqa: B306 + continue + if not confirmation_prompt: + return result + while True: + value2 = prompt_func(confirmation_prompt) + is_empty = not value and not value2 + if value2 or is_empty: + break + if value == value2: + return result + echo(_("Error: The two entered values do not match."), err=err) + + +def confirm( + text: str, + default: t.Optional[bool] = False, + abort: bool = False, + prompt_suffix: str = ": ", + show_default: bool = True, + err: bool = False, +) -> bool: + """Prompts for confirmation (yes/no question). + + If the user aborts the input by sending a interrupt signal this + function will catch it and raise a :exc:`Abort` exception. + + :param text: the question to ask. + :param default: The default value to use when no input is given. If + ``None``, repeat until input is given. + :param abort: if this is set to `True` a negative answer aborts the + exception by raising :exc:`Abort`. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + + .. versionchanged:: 8.0 + Repeat until input is given if ``default`` is ``None``. + + .. versionadded:: 4.0 + Added the ``err`` parameter. + """ + prompt = _build_prompt( + text, + prompt_suffix, + show_default, + "y/n" if default is None else ("Y/n" if default else "y/N"), + ) + + while True: + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(prompt.rstrip(" "), nl=False, err=err) + # Echo a space to stdout to work around an issue where + # readline causes backspace to clear the whole line. + value = visible_prompt_func(" ").lower().strip() + except (KeyboardInterrupt, EOFError): + raise Abort() from None + if value in ("y", "yes"): + rv = True + elif value in ("n", "no"): + rv = False + elif default is not None and value == "": + rv = default + else: + echo(_("Error: invalid input"), err=err) + continue + break + if abort and not rv: + raise Abort() + return rv + + +def echo_via_pager( + text_or_generator: t.Union[t.Iterable[str], t.Callable[[], t.Iterable[str]], str], + color: t.Optional[bool] = None, +) -> None: + """This function takes a text and shows it via an environment specific + pager on stdout. + + .. versionchanged:: 3.0 + Added the `color` flag. + + :param text_or_generator: the text to page, or alternatively, a + generator emitting the text to page. + :param color: controls if the pager supports ANSI colors or not. The + default is autodetection. + """ + color = resolve_color_default(color) + + if inspect.isgeneratorfunction(text_or_generator): + i = t.cast(t.Callable[[], t.Iterable[str]], text_or_generator)() + elif isinstance(text_or_generator, str): + i = [text_or_generator] + else: + i = iter(t.cast(t.Iterable[str], text_or_generator)) + + # convert every element of i to a text type if necessary + text_generator = (el if isinstance(el, str) else str(el) for el in i) + + from ._termui_impl import pager + + return pager(itertools.chain(text_generator, "\n"), color) + + +def progressbar( + iterable: t.Optional[t.Iterable[V]] = None, + length: t.Optional[int] = None, + label: t.Optional[str] = None, + show_eta: bool = True, + show_percent: t.Optional[bool] = None, + show_pos: bool = False, + item_show_func: t.Optional[t.Callable[[t.Optional[V]], t.Optional[str]]] = None, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.Optional[t.TextIO] = None, + color: t.Optional[bool] = None, + update_min_steps: int = 1, +) -> "ProgressBar[V]": + """This function creates an iterable context manager that can be used + to iterate over something while showing a progress bar. It will + either iterate over the `iterable` or `length` items (that are counted + up). While iteration happens, this function will print a rendered + progress bar to the given `file` (defaults to stdout) and will attempt + to calculate remaining time and more. By default, this progress bar + will not be rendered if the file is not a terminal. + + The context manager creates the progress bar. When the context + manager is entered the progress bar is already created. With every + iteration over the progress bar, the iterable passed to the bar is + advanced and the bar is updated. When the context manager exits, + a newline is printed and the progress bar is finalized on screen. + + Note: The progress bar is currently designed for use cases where the + total progress can be expected to take at least several seconds. + Because of this, the ProgressBar class object won't display + progress that is considered too fast, and progress where the time + between steps is less than a second. + + No printing must happen or the progress bar will be unintentionally + destroyed. + + Example usage:: + + with progressbar(items) as bar: + for item in bar: + do_something_with(item) + + Alternatively, if no iterable is specified, one can manually update the + progress bar through the `update()` method instead of directly + iterating over the progress bar. The update method accepts the number + of steps to increment the bar with:: + + with progressbar(length=chunks.total_bytes) as bar: + for chunk in chunks: + process_chunk(chunk) + bar.update(chunks.bytes) + + The ``update()`` method also takes an optional value specifying the + ``current_item`` at the new position. This is useful when used + together with ``item_show_func`` to customize the output for each + manual step:: + + with click.progressbar( + length=total_size, + label='Unzipping archive', + item_show_func=lambda a: a.filename + ) as bar: + for archive in zip_file: + archive.extract() + bar.update(archive.size, archive) + + :param iterable: an iterable to iterate over. If not provided the length + is required. + :param length: the number of items to iterate over. By default the + progressbar will attempt to ask the iterator about its + length, which might or might not work. If an iterable is + also provided this parameter can be used to override the + length. If an iterable is not provided the progress bar + will iterate over a range of that length. + :param label: the label to show next to the progress bar. + :param show_eta: enables or disables the estimated time display. This is + automatically disabled if the length cannot be + determined. + :param show_percent: enables or disables the percentage display. The + default is `True` if the iterable has a length or + `False` if not. + :param show_pos: enables or disables the absolute position display. The + default is `False`. + :param item_show_func: A function called with the current item which + can return a string to show next to the progress bar. If the + function returns ``None`` nothing is shown. The current item can + be ``None``, such as when entering and exiting the bar. + :param fill_char: the character to use to show the filled part of the + progress bar. + :param empty_char: the character to use to show the non-filled part of + the progress bar. + :param bar_template: the format string to use as template for the bar. + The parameters in it are ``label`` for the label, + ``bar`` for the progress bar and ``info`` for the + info section. + :param info_sep: the separator between multiple info items (eta etc.) + :param width: the width of the progress bar in characters, 0 means full + terminal width + :param file: The file to write to. If this is not a terminal then + only the label is printed. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are included anywhere in the progress bar output + which is not the case by default. + :param update_min_steps: Render only when this many updates have + completed. This allows tuning for very fast iterators. + + .. versionchanged:: 8.0 + Output is shown even if execution time is less than 0.5 seconds. + + .. versionchanged:: 8.0 + ``item_show_func`` shows the current item, not the previous one. + + .. versionchanged:: 8.0 + Labels are echoed if the output is not a TTY. Reverts a change + in 7.0 that removed all output. + + .. versionadded:: 8.0 + Added the ``update_min_steps`` parameter. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. Added the ``update`` method to + the object. + + .. versionadded:: 2.0 + """ + from ._termui_impl import ProgressBar + + color = resolve_color_default(color) + return ProgressBar( + iterable=iterable, + length=length, + show_eta=show_eta, + show_percent=show_percent, + show_pos=show_pos, + item_show_func=item_show_func, + fill_char=fill_char, + empty_char=empty_char, + bar_template=bar_template, + info_sep=info_sep, + file=file, + label=label, + width=width, + color=color, + update_min_steps=update_min_steps, + ) + + +def clear() -> None: + """Clears the terminal screen. This will have the effect of clearing + the whole visible space of the terminal and moving the cursor to the + top left. This does not do anything if not connected to a terminal. + + .. versionadded:: 2.0 + """ + if not isatty(sys.stdout): + return + if WIN: + os.system("cls") + else: + sys.stdout.write("\033[2J\033[1;1H") + + +def _interpret_color( + color: t.Union[int, t.Tuple[int, int, int], str], offset: int = 0 +) -> str: + if isinstance(color, int): + return f"{38 + offset};5;{color:d}" + + if isinstance(color, (tuple, list)): + r, g, b = color + return f"{38 + offset};2;{r:d};{g:d};{b:d}" + + return str(_ansi_colors[color] + offset) + + +def style( + text: t.Any, + fg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None, + bg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None, + bold: t.Optional[bool] = None, + dim: t.Optional[bool] = None, + underline: t.Optional[bool] = None, + overline: t.Optional[bool] = None, + italic: t.Optional[bool] = None, + blink: t.Optional[bool] = None, + reverse: t.Optional[bool] = None, + strikethrough: t.Optional[bool] = None, + reset: bool = True, +) -> str: + """Styles a text with ANSI styles and returns the new string. By + default the styling is self contained which means that at the end + of the string a reset code is issued. This can be prevented by + passing ``reset=False``. + + Examples:: + + click.echo(click.style('Hello World!', fg='green')) + click.echo(click.style('ATTENTION!', blink=True)) + click.echo(click.style('Some things', reverse=True, fg='cyan')) + click.echo(click.style('More colors', fg=(255, 12, 128), bg=117)) + + Supported color names: + + * ``black`` (might be a gray) + * ``red`` + * ``green`` + * ``yellow`` (might be an orange) + * ``blue`` + * ``magenta`` + * ``cyan`` + * ``white`` (might be light gray) + * ``bright_black`` + * ``bright_red`` + * ``bright_green`` + * ``bright_yellow`` + * ``bright_blue`` + * ``bright_magenta`` + * ``bright_cyan`` + * ``bright_white`` + * ``reset`` (reset the color code only) + + If the terminal supports it, color may also be specified as: + + - An integer in the interval [0, 255]. The terminal must support + 8-bit/256-color mode. + - An RGB tuple of three integers in [0, 255]. The terminal must + support 24-bit/true-color mode. + + See https://en.wikipedia.org/wiki/ANSI_color and + https://gist.github.com/XVilka/8346728 for more information. + + :param text: the string to style with ansi codes. + :param fg: if provided this will become the foreground color. + :param bg: if provided this will become the background color. + :param bold: if provided this will enable or disable bold mode. + :param dim: if provided this will enable or disable dim mode. This is + badly supported. + :param underline: if provided this will enable or disable underline. + :param overline: if provided this will enable or disable overline. + :param italic: if provided this will enable or disable italic. + :param blink: if provided this will enable or disable blinking. + :param reverse: if provided this will enable or disable inverse + rendering (foreground becomes background and the + other way round). + :param strikethrough: if provided this will enable or disable + striking through text. + :param reset: by default a reset-all code is added at the end of the + string which means that styles do not carry over. This + can be disabled to compose styles. + + .. versionchanged:: 8.0 + A non-string ``message`` is converted to a string. + + .. versionchanged:: 8.0 + Added support for 256 and RGB color codes. + + .. versionchanged:: 8.0 + Added the ``strikethrough``, ``italic``, and ``overline`` + parameters. + + .. versionchanged:: 7.0 + Added support for bright colors. + + .. versionadded:: 2.0 + """ + if not isinstance(text, str): + text = str(text) + + bits = [] + + if fg: + try: + bits.append(f"\033[{_interpret_color(fg)}m") + except KeyError: + raise TypeError(f"Unknown color {fg!r}") from None + + if bg: + try: + bits.append(f"\033[{_interpret_color(bg, 10)}m") + except KeyError: + raise TypeError(f"Unknown color {bg!r}") from None + + if bold is not None: + bits.append(f"\033[{1 if bold else 22}m") + if dim is not None: + bits.append(f"\033[{2 if dim else 22}m") + if underline is not None: + bits.append(f"\033[{4 if underline else 24}m") + if overline is not None: + bits.append(f"\033[{53 if overline else 55}m") + if italic is not None: + bits.append(f"\033[{3 if italic else 23}m") + if blink is not None: + bits.append(f"\033[{5 if blink else 25}m") + if reverse is not None: + bits.append(f"\033[{7 if reverse else 27}m") + if strikethrough is not None: + bits.append(f"\033[{9 if strikethrough else 29}m") + bits.append(text) + if reset: + bits.append(_ansi_reset_all) + return "".join(bits) + + +def unstyle(text: str) -> str: + """Removes ANSI styling information from a string. Usually it's not + necessary to use this function as Click's echo function will + automatically remove styling if necessary. + + .. versionadded:: 2.0 + + :param text: the text to remove style information from. + """ + return strip_ansi(text) + + +def secho( + message: t.Optional[t.Any] = None, + file: t.Optional[t.IO[t.AnyStr]] = None, + nl: bool = True, + err: bool = False, + color: t.Optional[bool] = None, + **styles: t.Any, +) -> None: + """This function combines :func:`echo` and :func:`style` into one + call. As such the following two calls are the same:: + + click.secho('Hello World!', fg='green') + click.echo(click.style('Hello World!', fg='green')) + + All keyword arguments are forwarded to the underlying functions + depending on which one they go with. + + Non-string types will be converted to :class:`str`. However, + :class:`bytes` are passed directly to :meth:`echo` without applying + style. If you want to style bytes that represent text, call + :meth:`bytes.decode` first. + + .. versionchanged:: 8.0 + A non-string ``message`` is converted to a string. Bytes are + passed through without style applied. + + .. versionadded:: 2.0 + """ + if message is not None and not isinstance(message, (bytes, bytearray)): + message = style(message, **styles) + + return echo(message, file=file, nl=nl, err=err, color=color) + + +def edit( + text: t.Optional[t.AnyStr] = None, + editor: t.Optional[str] = None, + env: t.Optional[t.Mapping[str, str]] = None, + require_save: bool = True, + extension: str = ".txt", + filename: t.Optional[str] = None, +) -> t.Optional[t.AnyStr]: + r"""Edits the given text in the defined editor. If an editor is given + (should be the full path to the executable but the regular operating + system search path is used for finding the executable) it overrides + the detected editor. Optionally, some environment variables can be + used. If the editor is closed without changes, `None` is returned. In + case a file is edited directly the return value is always `None` and + `require_save` and `extension` are ignored. + + If the editor cannot be opened a :exc:`UsageError` is raised. + + Note for Windows: to simplify cross-platform usage, the newlines are + automatically converted from POSIX to Windows and vice versa. As such, + the message here will have ``\n`` as newline markers. + + :param text: the text to edit. + :param editor: optionally the editor to use. Defaults to automatic + detection. + :param env: environment variables to forward to the editor. + :param require_save: if this is true, then not saving in the editor + will make the return value become `None`. + :param extension: the extension to tell the editor about. This defaults + to `.txt` but changing this might change syntax + highlighting. + :param filename: if provided it will edit this file instead of the + provided text contents. It will not use a temporary + file as an indirection in that case. + """ + from ._termui_impl import Editor + + ed = Editor(editor=editor, env=env, require_save=require_save, extension=extension) + + if filename is None: + return ed.edit(text) + + ed.edit_file(filename) + return None + + +def launch(url: str, wait: bool = False, locate: bool = False) -> int: + """This function launches the given URL (or filename) in the default + viewer application for this file type. If this is an executable, it + might launch the executable in a new session. The return value is + the exit code of the launched application. Usually, ``0`` indicates + success. + + Examples:: + + click.launch('https://click.palletsprojects.com/') + click.launch('/my/downloaded/file', locate=True) + + .. versionadded:: 2.0 + + :param url: URL or filename of the thing to launch. + :param wait: Wait for the program to exit before returning. This + only works if the launched program blocks. In particular, + ``xdg-open`` on Linux does not block. + :param locate: if this is set to `True` then instead of launching the + application associated with the URL it will attempt to + launch a file manager with the file located. This + might have weird effects if the URL does not point to + the filesystem. + """ + from ._termui_impl import open_url + + return open_url(url, wait=wait, locate=locate) + + +# If this is provided, getchar() calls into this instead. This is used +# for unittesting purposes. +_getchar: t.Optional[t.Callable[[bool], str]] = None + + +def getchar(echo: bool = False) -> str: + """Fetches a single character from the terminal and returns it. This + will always return a unicode character and under certain rare + circumstances this might return more than one character. The + situations which more than one character is returned is when for + whatever reason multiple characters end up in the terminal buffer or + standard input was not actually a terminal. + + Note that this will always read from the terminal, even if something + is piped into the standard input. + + Note for Windows: in rare cases when typing non-ASCII characters, this + function might wait for a second character and then return both at once. + This is because certain Unicode characters look like special-key markers. + + .. versionadded:: 2.0 + + :param echo: if set to `True`, the character read will also show up on + the terminal. The default is to not show it. + """ + global _getchar + + if _getchar is None: + from ._termui_impl import getchar as f + + _getchar = f + + return _getchar(echo) + + +def raw_terminal() -> t.ContextManager[int]: + from ._termui_impl import raw_terminal as f + + return f() + + +def pause(info: t.Optional[str] = None, err: bool = False) -> None: + """This command stops execution and waits for the user to press any + key to continue. This is similar to the Windows batch "pause" + command. If the program is not run through a terminal, this command + will instead do nothing. + + .. versionadded:: 2.0 + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param info: The message to print before pausing. Defaults to + ``"Press any key to continue..."``. + :param err: if set to message goes to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + if not isatty(sys.stdin) or not isatty(sys.stdout): + return + + if info is None: + info = _("Press any key to continue...") + + try: + if info: + echo(info, nl=False, err=err) + try: + getchar() + except (KeyboardInterrupt, EOFError): + pass + finally: + if info: + echo(err=err) diff --git a/.venv/Lib/site-packages/click/testing.py b/.venv/Lib/site-packages/click/testing.py new file mode 100644 index 000000000..e395c2edf --- /dev/null +++ b/.venv/Lib/site-packages/click/testing.py @@ -0,0 +1,479 @@ +import contextlib +import io +import os +import shlex +import shutil +import sys +import tempfile +import typing as t +from types import TracebackType + +from . import formatting +from . import termui +from . import utils +from ._compat import _find_binary_reader + +if t.TYPE_CHECKING: + from .core import BaseCommand + + +class EchoingStdin: + def __init__(self, input: t.BinaryIO, output: t.BinaryIO) -> None: + self._input = input + self._output = output + self._paused = False + + def __getattr__(self, x: str) -> t.Any: + return getattr(self._input, x) + + def _echo(self, rv: bytes) -> bytes: + if not self._paused: + self._output.write(rv) + + return rv + + def read(self, n: int = -1) -> bytes: + return self._echo(self._input.read(n)) + + def read1(self, n: int = -1) -> bytes: + return self._echo(self._input.read1(n)) # type: ignore + + def readline(self, n: int = -1) -> bytes: + return self._echo(self._input.readline(n)) + + def readlines(self) -> t.List[bytes]: + return [self._echo(x) for x in self._input.readlines()] + + def __iter__(self) -> t.Iterator[bytes]: + return iter(self._echo(x) for x in self._input) + + def __repr__(self) -> str: + return repr(self._input) + + +@contextlib.contextmanager +def _pause_echo(stream: t.Optional[EchoingStdin]) -> t.Iterator[None]: + if stream is None: + yield + else: + stream._paused = True + yield + stream._paused = False + + +class _NamedTextIOWrapper(io.TextIOWrapper): + def __init__( + self, buffer: t.BinaryIO, name: str, mode: str, **kwargs: t.Any + ) -> None: + super().__init__(buffer, **kwargs) + self._name = name + self._mode = mode + + @property + def name(self) -> str: + return self._name + + @property + def mode(self) -> str: + return self._mode + + +def make_input_stream( + input: t.Optional[t.Union[str, bytes, t.IO]], charset: str +) -> t.BinaryIO: + # Is already an input stream. + if hasattr(input, "read"): + rv = _find_binary_reader(t.cast(t.IO, input)) + + if rv is not None: + return rv + + raise TypeError("Could not find binary reader for input stream.") + + if input is None: + input = b"" + elif isinstance(input, str): + input = input.encode(charset) + + return io.BytesIO(t.cast(bytes, input)) + + +class Result: + """Holds the captured result of an invoked CLI script.""" + + def __init__( + self, + runner: "CliRunner", + stdout_bytes: bytes, + stderr_bytes: t.Optional[bytes], + return_value: t.Any, + exit_code: int, + exception: t.Optional[BaseException], + exc_info: t.Optional[ + t.Tuple[t.Type[BaseException], BaseException, TracebackType] + ] = None, + ): + #: The runner that created the result + self.runner = runner + #: The standard output as bytes. + self.stdout_bytes = stdout_bytes + #: The standard error as bytes, or None if not available + self.stderr_bytes = stderr_bytes + #: The value returned from the invoked command. + #: + #: .. versionadded:: 8.0 + self.return_value = return_value + #: The exit code as integer. + self.exit_code = exit_code + #: The exception that happened if one did. + self.exception = exception + #: The traceback + self.exc_info = exc_info + + @property + def output(self) -> str: + """The (standard) output as unicode string.""" + return self.stdout + + @property + def stdout(self) -> str: + """The standard output as unicode string.""" + return self.stdout_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + @property + def stderr(self) -> str: + """The standard error as unicode string.""" + if self.stderr_bytes is None: + raise ValueError("stderr not separately captured") + return self.stderr_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + def __repr__(self) -> str: + exc_str = repr(self.exception) if self.exception else "okay" + return f"<{type(self).__name__} {exc_str}>" + + +class CliRunner: + """The CLI runner provides functionality to invoke a Click command line + script for unittesting purposes in a isolated environment. This only + works in single-threaded systems without any concurrency as it changes the + global interpreter state. + + :param charset: the character set for the input and output data. + :param env: a dictionary with environment variables for overriding. + :param echo_stdin: if this is set to `True`, then reading from stdin writes + to stdout. This is useful for showing examples in + some circumstances. Note that regular prompts + will automatically echo the input. + :param mix_stderr: if this is set to `False`, then stdout and stderr are + preserved as independent streams. This is useful for + Unix-philosophy apps that have predictable stdout and + noisy stderr, such that each may be measured + independently + """ + + def __init__( + self, + charset: str = "utf-8", + env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, + echo_stdin: bool = False, + mix_stderr: bool = True, + ) -> None: + self.charset = charset + self.env = env or {} + self.echo_stdin = echo_stdin + self.mix_stderr = mix_stderr + + def get_default_prog_name(self, cli: "BaseCommand") -> str: + """Given a command object it will return the default program name + for it. The default is the `name` attribute or ``"root"`` if not + set. + """ + return cli.name or "root" + + def make_env( + self, overrides: t.Optional[t.Mapping[str, t.Optional[str]]] = None + ) -> t.Mapping[str, t.Optional[str]]: + """Returns the environment overrides for invoking a script.""" + rv = dict(self.env) + if overrides: + rv.update(overrides) + return rv + + @contextlib.contextmanager + def isolation( + self, + input: t.Optional[t.Union[str, bytes, t.IO]] = None, + env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, + color: bool = False, + ) -> t.Iterator[t.Tuple[io.BytesIO, t.Optional[io.BytesIO]]]: + """A context manager that sets up the isolation for invoking of a + command line tool. This sets up stdin with the given input data + and `os.environ` with the overrides from the given dictionary. + This also rebinds some internals in Click to be mocked (like the + prompt functionality). + + This is automatically done in the :meth:`invoke` method. + + :param input: the input stream to put into sys.stdin. + :param env: the environment overrides as dictionary. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + + .. versionchanged:: 8.0 + ``stderr`` is opened with ``errors="backslashreplace"`` + instead of the default ``"strict"``. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + """ + bytes_input = make_input_stream(input, self.charset) + echo_input = None + + old_stdin = sys.stdin + old_stdout = sys.stdout + old_stderr = sys.stderr + old_forced_width = formatting.FORCED_WIDTH + formatting.FORCED_WIDTH = 80 + + env = self.make_env(env) + + bytes_output = io.BytesIO() + + if self.echo_stdin: + bytes_input = echo_input = t.cast( + t.BinaryIO, EchoingStdin(bytes_input, bytes_output) + ) + + sys.stdin = text_input = _NamedTextIOWrapper( + bytes_input, encoding=self.charset, name="", mode="r" + ) + + if self.echo_stdin: + # Force unbuffered reads, otherwise TextIOWrapper reads a + # large chunk which is echoed early. + text_input._CHUNK_SIZE = 1 # type: ignore + + sys.stdout = _NamedTextIOWrapper( + bytes_output, encoding=self.charset, name="", mode="w" + ) + + bytes_error = None + if self.mix_stderr: + sys.stderr = sys.stdout + else: + bytes_error = io.BytesIO() + sys.stderr = _NamedTextIOWrapper( + bytes_error, + encoding=self.charset, + name="", + mode="w", + errors="backslashreplace", + ) + + @_pause_echo(echo_input) # type: ignore + def visible_input(prompt: t.Optional[str] = None) -> str: + sys.stdout.write(prompt or "") + val = text_input.readline().rstrip("\r\n") + sys.stdout.write(f"{val}\n") + sys.stdout.flush() + return val + + @_pause_echo(echo_input) # type: ignore + def hidden_input(prompt: t.Optional[str] = None) -> str: + sys.stdout.write(f"{prompt or ''}\n") + sys.stdout.flush() + return text_input.readline().rstrip("\r\n") + + @_pause_echo(echo_input) # type: ignore + def _getchar(echo: bool) -> str: + char = sys.stdin.read(1) + + if echo: + sys.stdout.write(char) + + sys.stdout.flush() + return char + + default_color = color + + def should_strip_ansi( + stream: t.Optional[t.IO] = None, color: t.Optional[bool] = None + ) -> bool: + if color is None: + return not default_color + return not color + + old_visible_prompt_func = termui.visible_prompt_func + old_hidden_prompt_func = termui.hidden_prompt_func + old__getchar_func = termui._getchar + old_should_strip_ansi = utils.should_strip_ansi # type: ignore + termui.visible_prompt_func = visible_input + termui.hidden_prompt_func = hidden_input + termui._getchar = _getchar + utils.should_strip_ansi = should_strip_ansi # type: ignore + + old_env = {} + try: + for key, value in env.items(): + old_env[key] = os.environ.get(key) + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + yield (bytes_output, bytes_error) + finally: + for key, value in old_env.items(): + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + sys.stdout = old_stdout + sys.stderr = old_stderr + sys.stdin = old_stdin + termui.visible_prompt_func = old_visible_prompt_func + termui.hidden_prompt_func = old_hidden_prompt_func + termui._getchar = old__getchar_func + utils.should_strip_ansi = old_should_strip_ansi # type: ignore + formatting.FORCED_WIDTH = old_forced_width + + def invoke( + self, + cli: "BaseCommand", + args: t.Optional[t.Union[str, t.Sequence[str]]] = None, + input: t.Optional[t.Union[str, bytes, t.IO]] = None, + env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, + catch_exceptions: bool = True, + color: bool = False, + **extra: t.Any, + ) -> Result: + """Invokes a command in an isolated environment. The arguments are + forwarded directly to the command line script, the `extra` keyword + arguments are passed to the :meth:`~clickpkg.Command.main` function of + the command. + + This returns a :class:`Result` object. + + :param cli: the command to invoke + :param args: the arguments to invoke. It may be given as an iterable + or a string. When given as string it will be interpreted + as a Unix shell command. More details at + :func:`shlex.split`. + :param input: the input data for `sys.stdin`. + :param env: the environment overrides. + :param catch_exceptions: Whether to catch any other exceptions than + ``SystemExit``. + :param extra: the keyword arguments to pass to :meth:`main`. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + + .. versionchanged:: 8.0 + The result object has the ``return_value`` attribute with + the value returned from the invoked command. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + + .. versionchanged:: 3.0 + Added the ``catch_exceptions`` parameter. + + .. versionchanged:: 3.0 + The result object has the ``exc_info`` attribute with the + traceback if available. + """ + exc_info = None + with self.isolation(input=input, env=env, color=color) as outstreams: + return_value = None + exception: t.Optional[BaseException] = None + exit_code = 0 + + if isinstance(args, str): + args = shlex.split(args) + + try: + prog_name = extra.pop("prog_name") + except KeyError: + prog_name = self.get_default_prog_name(cli) + + try: + return_value = cli.main(args=args or (), prog_name=prog_name, **extra) + except SystemExit as e: + exc_info = sys.exc_info() + e_code = t.cast(t.Optional[t.Union[int, t.Any]], e.code) + + if e_code is None: + e_code = 0 + + if e_code != 0: + exception = e + + if not isinstance(e_code, int): + sys.stdout.write(str(e_code)) + sys.stdout.write("\n") + e_code = 1 + + exit_code = e_code + + except Exception as e: + if not catch_exceptions: + raise + exception = e + exit_code = 1 + exc_info = sys.exc_info() + finally: + sys.stdout.flush() + stdout = outstreams[0].getvalue() + if self.mix_stderr: + stderr = None + else: + stderr = outstreams[1].getvalue() # type: ignore + + return Result( + runner=self, + stdout_bytes=stdout, + stderr_bytes=stderr, + return_value=return_value, + exit_code=exit_code, + exception=exception, + exc_info=exc_info, # type: ignore + ) + + @contextlib.contextmanager + def isolated_filesystem( + self, temp_dir: t.Optional[t.Union[str, os.PathLike]] = None + ) -> t.Iterator[str]: + """A context manager that creates a temporary directory and + changes the current working directory to it. This isolates tests + that affect the contents of the CWD to prevent them from + interfering with each other. + + :param temp_dir: Create the temporary directory under this + directory. If given, the created directory is not removed + when exiting. + + .. versionchanged:: 8.0 + Added the ``temp_dir`` parameter. + """ + cwd = os.getcwd() + dt = tempfile.mkdtemp(dir=temp_dir) # type: ignore[type-var] + os.chdir(dt) + + try: + yield t.cast(str, dt) + finally: + os.chdir(cwd) + + if temp_dir is None: + try: + shutil.rmtree(dt) + except OSError: # noqa: B014 + pass diff --git a/.venv/Lib/site-packages/click/types.py b/.venv/Lib/site-packages/click/types.py new file mode 100644 index 000000000..b45ee53d0 --- /dev/null +++ b/.venv/Lib/site-packages/click/types.py @@ -0,0 +1,1073 @@ +import os +import stat +import typing as t +from datetime import datetime +from gettext import gettext as _ +from gettext import ngettext + +from ._compat import _get_argv_encoding +from ._compat import get_filesystem_encoding +from ._compat import open_stream +from .exceptions import BadParameter +from .utils import LazyFile +from .utils import safecall + +if t.TYPE_CHECKING: + import typing_extensions as te + from .core import Context + from .core import Parameter + from .shell_completion import CompletionItem + + +class ParamType: + """Represents the type of a parameter. Validates and converts values + from the command line or Python into the correct type. + + To implement a custom type, subclass and implement at least the + following: + + - The :attr:`name` class attribute must be set. + - Calling an instance of the type with ``None`` must return + ``None``. This is already implemented by default. + - :meth:`convert` must convert string values to the correct type. + - :meth:`convert` must accept values that are already the correct + type. + - It must be able to convert a value if the ``ctx`` and ``param`` + arguments are ``None``. This can occur when converting prompt + input. + """ + + is_composite: t.ClassVar[bool] = False + arity: t.ClassVar[int] = 1 + + #: the descriptive name of this type + name: str + + #: if a list of this type is expected and the value is pulled from a + #: string environment variable, this is what splits it up. `None` + #: means any whitespace. For all parameters the general rule is that + #: whitespace splits them up. The exception are paths and files which + #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on + #: Windows). + envvar_list_splitter: t.ClassVar[t.Optional[str]] = None + + def to_info_dict(self) -> t.Dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + .. versionadded:: 8.0 + """ + # The class name without the "ParamType" suffix. + param_type = type(self).__name__.partition("ParamType")[0] + param_type = param_type.partition("ParameterType")[0] + + # Custom subclasses might not remember to set a name. + if hasattr(self, "name"): + name = self.name + else: + name = param_type + + return {"param_type": param_type, "name": name} + + def __call__( + self, + value: t.Any, + param: t.Optional["Parameter"] = None, + ctx: t.Optional["Context"] = None, + ) -> t.Any: + if value is not None: + return self.convert(value, param, ctx) + + def get_metavar(self, param: "Parameter") -> t.Optional[str]: + """Returns the metavar default for this param if it provides one.""" + + def get_missing_message(self, param: "Parameter") -> t.Optional[str]: + """Optionally might return extra information about a missing + parameter. + + .. versionadded:: 2.0 + """ + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + """Convert the value to the correct type. This is not called if + the value is ``None`` (the missing value). + + This must accept string values from the command line, as well as + values that are already the correct type. It may also convert + other compatible types. + + The ``param`` and ``ctx`` arguments may be ``None`` in certain + situations, such as when converting prompt input. + + If the value cannot be converted, call :meth:`fail` with a + descriptive message. + + :param value: The value to convert. + :param param: The parameter that is using this type to convert + its value. May be ``None``. + :param ctx: The current context that arrived at this value. May + be ``None``. + """ + return value + + def split_envvar_value(self, rv: str) -> t.Sequence[str]: + """Given a value from an environment variable this splits it up + into small chunks depending on the defined envvar list splitter. + + If the splitter is set to `None`, which means that whitespace splits, + then leading and trailing whitespace is ignored. Otherwise, leading + and trailing splitters usually lead to empty items being included. + """ + return (rv or "").split(self.envvar_list_splitter) + + def fail( + self, + message: str, + param: t.Optional["Parameter"] = None, + ctx: t.Optional["Context"] = None, + ) -> "t.NoReturn": + """Helper method to fail with an invalid value message.""" + raise BadParameter(message, ctx=ctx, param=param) + + def shell_complete( + self, ctx: "Context", param: "Parameter", incomplete: str + ) -> t.List["CompletionItem"]: + """Return a list of + :class:`~click.shell_completion.CompletionItem` objects for the + incomplete value. Most types do not provide completions, but + some do, and this allows custom types to provide custom + completions as well. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + return [] + + +class CompositeParamType(ParamType): + is_composite = True + + @property + def arity(self) -> int: # type: ignore + raise NotImplementedError() + + +class FuncParamType(ParamType): + def __init__(self, func: t.Callable[[t.Any], t.Any]) -> None: + self.name = func.__name__ + self.func = func + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["func"] = self.func + return info_dict + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + try: + return self.func(value) + except ValueError: + try: + value = str(value) + except UnicodeError: + value = value.decode("utf-8", "replace") + + self.fail(value, param, ctx) + + +class UnprocessedParamType(ParamType): + name = "text" + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + return value + + def __repr__(self) -> str: + return "UNPROCESSED" + + +class StringParamType(ParamType): + name = "text" + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + if isinstance(value, bytes): + enc = _get_argv_encoding() + try: + value = value.decode(enc) + except UnicodeError: + fs_enc = get_filesystem_encoding() + if fs_enc != enc: + try: + value = value.decode(fs_enc) + except UnicodeError: + value = value.decode("utf-8", "replace") + else: + value = value.decode("utf-8", "replace") + return value + return str(value) + + def __repr__(self) -> str: + return "STRING" + + +class Choice(ParamType): + """The choice type allows a value to be checked against a fixed set + of supported values. All of these values have to be strings. + + You should only pass a list or tuple of choices. Other iterables + (like generators) may lead to surprising results. + + The resulting value will always be one of the originally passed choices + regardless of ``case_sensitive`` or any ``ctx.token_normalize_func`` + being specified. + + See :ref:`choice-opts` for an example. + + :param case_sensitive: Set to false to make choices case + insensitive. Defaults to true. + """ + + name = "choice" + + def __init__(self, choices: t.Sequence[str], case_sensitive: bool = True) -> None: + self.choices = choices + self.case_sensitive = case_sensitive + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["choices"] = self.choices + info_dict["case_sensitive"] = self.case_sensitive + return info_dict + + def get_metavar(self, param: "Parameter") -> str: + choices_str = "|".join(self.choices) + + # Use curly braces to indicate a required argument. + if param.required and param.param_type_name == "argument": + return f"{{{choices_str}}}" + + # Use square braces to indicate an option or optional argument. + return f"[{choices_str}]" + + def get_missing_message(self, param: "Parameter") -> str: + return _("Choose from:\n\t{choices}").format(choices=",\n\t".join(self.choices)) + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + # Match through normalization and case sensitivity + # first do token_normalize_func, then lowercase + # preserve original `value` to produce an accurate message in + # `self.fail` + normed_value = value + normed_choices = {choice: choice for choice in self.choices} + + if ctx is not None and ctx.token_normalize_func is not None: + normed_value = ctx.token_normalize_func(value) + normed_choices = { + ctx.token_normalize_func(normed_choice): original + for normed_choice, original in normed_choices.items() + } + + if not self.case_sensitive: + normed_value = normed_value.casefold() + normed_choices = { + normed_choice.casefold(): original + for normed_choice, original in normed_choices.items() + } + + if normed_value in normed_choices: + return normed_choices[normed_value] + + choices_str = ", ".join(map(repr, self.choices)) + self.fail( + ngettext( + "{value!r} is not {choice}.", + "{value!r} is not one of {choices}.", + len(self.choices), + ).format(value=value, choice=choices_str, choices=choices_str), + param, + ctx, + ) + + def __repr__(self) -> str: + return f"Choice({list(self.choices)})" + + def shell_complete( + self, ctx: "Context", param: "Parameter", incomplete: str + ) -> t.List["CompletionItem"]: + """Complete choices that start with the incomplete value. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + str_choices = map(str, self.choices) + + if self.case_sensitive: + matched = (c for c in str_choices if c.startswith(incomplete)) + else: + incomplete = incomplete.lower() + matched = (c for c in str_choices if c.lower().startswith(incomplete)) + + return [CompletionItem(c) for c in matched] + + +class DateTime(ParamType): + """The DateTime type converts date strings into `datetime` objects. + + The format strings which are checked are configurable, but default to some + common (non-timezone aware) ISO 8601 formats. + + When specifying *DateTime* formats, you should only pass a list or a tuple. + Other iterables, like generators, may lead to surprising results. + + The format strings are processed using ``datetime.strptime``, and this + consequently defines the format strings which are allowed. + + Parsing is tried using each format, in order, and the first format which + parses successfully is used. + + :param formats: A list or tuple of date format strings, in the order in + which they should be tried. Defaults to + ``'%Y-%m-%d'``, ``'%Y-%m-%dT%H:%M:%S'``, + ``'%Y-%m-%d %H:%M:%S'``. + """ + + name = "datetime" + + def __init__(self, formats: t.Optional[t.Sequence[str]] = None): + self.formats = formats or ["%Y-%m-%d", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%d %H:%M:%S"] + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["formats"] = self.formats + return info_dict + + def get_metavar(self, param: "Parameter") -> str: + return f"[{'|'.join(self.formats)}]" + + def _try_to_convert_date(self, value: t.Any, format: str) -> t.Optional[datetime]: + try: + return datetime.strptime(value, format) + except ValueError: + return None + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + if isinstance(value, datetime): + return value + + for format in self.formats: + converted = self._try_to_convert_date(value, format) + + if converted is not None: + return converted + + formats_str = ", ".join(map(repr, self.formats)) + self.fail( + ngettext( + "{value!r} does not match the format {format}.", + "{value!r} does not match the formats {formats}.", + len(self.formats), + ).format(value=value, format=formats_str, formats=formats_str), + param, + ctx, + ) + + def __repr__(self) -> str: + return "DateTime" + + +class _NumberParamTypeBase(ParamType): + _number_class: t.ClassVar[t.Type] + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + try: + return self._number_class(value) + except ValueError: + self.fail( + _("{value!r} is not a valid {number_type}.").format( + value=value, number_type=self.name + ), + param, + ctx, + ) + + +class _NumberRangeBase(_NumberParamTypeBase): + def __init__( + self, + min: t.Optional[float] = None, + max: t.Optional[float] = None, + min_open: bool = False, + max_open: bool = False, + clamp: bool = False, + ) -> None: + self.min = min + self.max = max + self.min_open = min_open + self.max_open = max_open + self.clamp = clamp + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + min=self.min, + max=self.max, + min_open=self.min_open, + max_open=self.max_open, + clamp=self.clamp, + ) + return info_dict + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + import operator + + rv = super().convert(value, param, ctx) + lt_min: bool = self.min is not None and ( + operator.le if self.min_open else operator.lt + )(rv, self.min) + gt_max: bool = self.max is not None and ( + operator.ge if self.max_open else operator.gt + )(rv, self.max) + + if self.clamp: + if lt_min: + return self._clamp(self.min, 1, self.min_open) # type: ignore + + if gt_max: + return self._clamp(self.max, -1, self.max_open) # type: ignore + + if lt_min or gt_max: + self.fail( + _("{value} is not in the range {range}.").format( + value=rv, range=self._describe_range() + ), + param, + ctx, + ) + + return rv + + def _clamp(self, bound: float, dir: "te.Literal[1, -1]", open: bool) -> float: + """Find the valid value to clamp to bound in the given + direction. + + :param bound: The boundary value. + :param dir: 1 or -1 indicating the direction to move. + :param open: If true, the range does not include the bound. + """ + raise NotImplementedError + + def _describe_range(self) -> str: + """Describe the range for use in help text.""" + if self.min is None: + op = "<" if self.max_open else "<=" + return f"x{op}{self.max}" + + if self.max is None: + op = ">" if self.min_open else ">=" + return f"x{op}{self.min}" + + lop = "<" if self.min_open else "<=" + rop = "<" if self.max_open else "<=" + return f"{self.min}{lop}x{rop}{self.max}" + + def __repr__(self) -> str: + clamp = " clamped" if self.clamp else "" + return f"<{type(self).__name__} {self._describe_range()}{clamp}>" + + +class IntParamType(_NumberParamTypeBase): + name = "integer" + _number_class = int + + def __repr__(self) -> str: + return "INT" + + +class IntRange(_NumberRangeBase, IntParamType): + """Restrict an :data:`click.INT` value to a range of accepted + values. See :ref:`ranges`. + + If ``min`` or ``max`` are not passed, any value is accepted in that + direction. If ``min_open`` or ``max_open`` are enabled, the + corresponding boundary is not included in the range. + + If ``clamp`` is enabled, a value outside the range is clamped to the + boundary instead of failing. + + .. versionchanged:: 8.0 + Added the ``min_open`` and ``max_open`` parameters. + """ + + name = "integer range" + + def _clamp( # type: ignore + self, bound: int, dir: "te.Literal[1, -1]", open: bool + ) -> int: + if not open: + return bound + + return bound + dir + + +class FloatParamType(_NumberParamTypeBase): + name = "float" + _number_class = float + + def __repr__(self) -> str: + return "FLOAT" + + +class FloatRange(_NumberRangeBase, FloatParamType): + """Restrict a :data:`click.FLOAT` value to a range of accepted + values. See :ref:`ranges`. + + If ``min`` or ``max`` are not passed, any value is accepted in that + direction. If ``min_open`` or ``max_open`` are enabled, the + corresponding boundary is not included in the range. + + If ``clamp`` is enabled, a value outside the range is clamped to the + boundary instead of failing. This is not supported if either + boundary is marked ``open``. + + .. versionchanged:: 8.0 + Added the ``min_open`` and ``max_open`` parameters. + """ + + name = "float range" + + def __init__( + self, + min: t.Optional[float] = None, + max: t.Optional[float] = None, + min_open: bool = False, + max_open: bool = False, + clamp: bool = False, + ) -> None: + super().__init__( + min=min, max=max, min_open=min_open, max_open=max_open, clamp=clamp + ) + + if (min_open or max_open) and clamp: + raise TypeError("Clamping is not supported for open bounds.") + + def _clamp(self, bound: float, dir: "te.Literal[1, -1]", open: bool) -> float: + if not open: + return bound + + # Could use Python 3.9's math.nextafter here, but clamping an + # open float range doesn't seem to be particularly useful. It's + # left up to the user to write a callback to do it if needed. + raise RuntimeError("Clamping is not supported for open bounds.") + + +class BoolParamType(ParamType): + name = "boolean" + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + if value in {False, True}: + return bool(value) + + norm = value.strip().lower() + + if norm in {"1", "true", "t", "yes", "y", "on"}: + return True + + if norm in {"0", "false", "f", "no", "n", "off"}: + return False + + self.fail( + _("{value!r} is not a valid boolean.").format(value=value), param, ctx + ) + + def __repr__(self) -> str: + return "BOOL" + + +class UUIDParameterType(ParamType): + name = "uuid" + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + import uuid + + if isinstance(value, uuid.UUID): + return value + + value = value.strip() + + try: + return uuid.UUID(value) + except ValueError: + self.fail( + _("{value!r} is not a valid UUID.").format(value=value), param, ctx + ) + + def __repr__(self) -> str: + return "UUID" + + +class File(ParamType): + """Declares a parameter to be a file for reading or writing. The file + is automatically closed once the context tears down (after the command + finished working). + + Files can be opened for reading or writing. The special value ``-`` + indicates stdin or stdout depending on the mode. + + By default, the file is opened for reading text data, but it can also be + opened in binary mode or for writing. The encoding parameter can be used + to force a specific encoding. + + The `lazy` flag controls if the file should be opened immediately or upon + first IO. The default is to be non-lazy for standard input and output + streams as well as files opened for reading, `lazy` otherwise. When opening a + file lazily for reading, it is still opened temporarily for validation, but + will not be held open until first IO. lazy is mainly useful when opening + for writing to avoid creating the file until it is needed. + + Starting with Click 2.0, files can also be opened atomically in which + case all writes go into a separate file in the same folder and upon + completion the file will be moved over to the original location. This + is useful if a file regularly read by other users is modified. + + See :ref:`file-args` for more information. + """ + + name = "filename" + envvar_list_splitter = os.path.pathsep + + def __init__( + self, + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", + lazy: t.Optional[bool] = None, + atomic: bool = False, + ) -> None: + self.mode = mode + self.encoding = encoding + self.errors = errors + self.lazy = lazy + self.atomic = atomic + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update(mode=self.mode, encoding=self.encoding) + return info_dict + + def resolve_lazy_flag(self, value: t.Any) -> bool: + if self.lazy is not None: + return self.lazy + if value == "-": + return False + elif "w" in self.mode: + return True + return False + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + try: + if hasattr(value, "read") or hasattr(value, "write"): + return value + + lazy = self.resolve_lazy_flag(value) + + if lazy: + f: t.IO = t.cast( + t.IO, + LazyFile( + value, self.mode, self.encoding, self.errors, atomic=self.atomic + ), + ) + + if ctx is not None: + ctx.call_on_close(f.close_intelligently) # type: ignore + + return f + + f, should_close = open_stream( + value, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + + # If a context is provided, we automatically close the file + # at the end of the context execution (or flush out). If a + # context does not exist, it's the caller's responsibility to + # properly close the file. This for instance happens when the + # type is used with prompts. + if ctx is not None: + if should_close: + ctx.call_on_close(safecall(f.close)) + else: + ctx.call_on_close(safecall(f.flush)) + + return f + except OSError as e: # noqa: B014 + self.fail(f"'{os.fsdecode(value)}': {e.strerror}", param, ctx) + + def shell_complete( + self, ctx: "Context", param: "Parameter", incomplete: str + ) -> t.List["CompletionItem"]: + """Return a special completion marker that tells the completion + system to use the shell to provide file path completions. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + return [CompletionItem(incomplete, type="file")] + + +class Path(ParamType): + """The ``Path`` type is similar to the :class:`File` type, but + returns the filename instead of an open file. Various checks can be + enabled to validate the type of file and permissions. + + :param exists: The file or directory needs to exist for the value to + be valid. If this is not set to ``True``, and the file does not + exist, then all further checks are silently skipped. + :param file_okay: Allow a file as a value. + :param dir_okay: Allow a directory as a value. + :param readable: if true, a readable check is performed. + :param writable: if true, a writable check is performed. + :param executable: if true, an executable check is performed. + :param resolve_path: Make the value absolute and resolve any + symlinks. A ``~`` is not expanded, as this is supposed to be + done by the shell only. + :param allow_dash: Allow a single dash as a value, which indicates + a standard stream (but does not open it). Use + :func:`~click.open_file` to handle opening this value. + :param path_type: Convert the incoming path value to this type. If + ``None``, keep Python's default, which is ``str``. Useful to + convert to :class:`pathlib.Path`. + + .. versionchanged:: 8.1 + Added the ``executable`` parameter. + + .. versionchanged:: 8.0 + Allow passing ``type=pathlib.Path``. + + .. versionchanged:: 6.0 + Added the ``allow_dash`` parameter. + """ + + envvar_list_splitter = os.path.pathsep + + def __init__( + self, + exists: bool = False, + file_okay: bool = True, + dir_okay: bool = True, + writable: bool = False, + readable: bool = True, + resolve_path: bool = False, + allow_dash: bool = False, + path_type: t.Optional[t.Type] = None, + executable: bool = False, + ): + self.exists = exists + self.file_okay = file_okay + self.dir_okay = dir_okay + self.readable = readable + self.writable = writable + self.executable = executable + self.resolve_path = resolve_path + self.allow_dash = allow_dash + self.type = path_type + + if self.file_okay and not self.dir_okay: + self.name = _("file") + elif self.dir_okay and not self.file_okay: + self.name = _("directory") + else: + self.name = _("path") + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + exists=self.exists, + file_okay=self.file_okay, + dir_okay=self.dir_okay, + writable=self.writable, + readable=self.readable, + allow_dash=self.allow_dash, + ) + return info_dict + + def coerce_path_result(self, rv: t.Any) -> t.Any: + if self.type is not None and not isinstance(rv, self.type): + if self.type is str: + rv = os.fsdecode(rv) + elif self.type is bytes: + rv = os.fsencode(rv) + else: + rv = self.type(rv) + + return rv + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + rv = value + + is_dash = self.file_okay and self.allow_dash and rv in (b"-", "-") + + if not is_dash: + if self.resolve_path: + # os.path.realpath doesn't resolve symlinks on Windows + # until Python 3.8. Use pathlib for now. + import pathlib + + rv = os.fsdecode(pathlib.Path(rv).resolve()) + + try: + st = os.stat(rv) + except OSError: + if not self.exists: + return self.coerce_path_result(rv) + self.fail( + _("{name} {filename!r} does not exist.").format( + name=self.name.title(), filename=os.fsdecode(value) + ), + param, + ctx, + ) + + if not self.file_okay and stat.S_ISREG(st.st_mode): + self.fail( + _("{name} {filename!r} is a file.").format( + name=self.name.title(), filename=os.fsdecode(value) + ), + param, + ctx, + ) + if not self.dir_okay and stat.S_ISDIR(st.st_mode): + self.fail( + _("{name} '{filename}' is a directory.").format( + name=self.name.title(), filename=os.fsdecode(value) + ), + param, + ctx, + ) + + if self.readable and not os.access(rv, os.R_OK): + self.fail( + _("{name} {filename!r} is not readable.").format( + name=self.name.title(), filename=os.fsdecode(value) + ), + param, + ctx, + ) + + if self.writable and not os.access(rv, os.W_OK): + self.fail( + _("{name} {filename!r} is not writable.").format( + name=self.name.title(), filename=os.fsdecode(value) + ), + param, + ctx, + ) + + if self.executable and not os.access(value, os.X_OK): + self.fail( + _("{name} {filename!r} is not executable.").format( + name=self.name.title(), filename=os.fsdecode(value) + ), + param, + ctx, + ) + + return self.coerce_path_result(rv) + + def shell_complete( + self, ctx: "Context", param: "Parameter", incomplete: str + ) -> t.List["CompletionItem"]: + """Return a special completion marker that tells the completion + system to use the shell to provide path completions for only + directories or any paths. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + type = "dir" if self.dir_okay and not self.file_okay else "file" + return [CompletionItem(incomplete, type=type)] + + +class Tuple(CompositeParamType): + """The default behavior of Click is to apply a type on a value directly. + This works well in most cases, except for when `nargs` is set to a fixed + count and different types should be used for different items. In this + case the :class:`Tuple` type can be used. This type can only be used + if `nargs` is set to a fixed number. + + For more information see :ref:`tuple-type`. + + This can be selected by using a Python tuple literal as a type. + + :param types: a list of types that should be used for the tuple items. + """ + + def __init__(self, types: t.Sequence[t.Union[t.Type, ParamType]]) -> None: + self.types = [convert_type(ty) for ty in types] + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["types"] = [t.to_info_dict() for t in self.types] + return info_dict + + @property + def name(self) -> str: # type: ignore + return f"<{' '.join(ty.name for ty in self.types)}>" + + @property + def arity(self) -> int: # type: ignore + return len(self.types) + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + len_type = len(self.types) + len_value = len(value) + + if len_value != len_type: + self.fail( + ngettext( + "{len_type} values are required, but {len_value} was given.", + "{len_type} values are required, but {len_value} were given.", + len_value, + ).format(len_type=len_type, len_value=len_value), + param=param, + ctx=ctx, + ) + + return tuple(ty(x, param, ctx) for ty, x in zip(self.types, value)) + + +def convert_type(ty: t.Optional[t.Any], default: t.Optional[t.Any] = None) -> ParamType: + """Find the most appropriate :class:`ParamType` for the given Python + type. If the type isn't provided, it can be inferred from a default + value. + """ + guessed_type = False + + if ty is None and default is not None: + if isinstance(default, (tuple, list)): + # If the default is empty, ty will remain None and will + # return STRING. + if default: + item = default[0] + + # A tuple of tuples needs to detect the inner types. + # Can't call convert recursively because that would + # incorrectly unwind the tuple to a single type. + if isinstance(item, (tuple, list)): + ty = tuple(map(type, item)) + else: + ty = type(item) + else: + ty = type(default) + + guessed_type = True + + if isinstance(ty, tuple): + return Tuple(ty) + + if isinstance(ty, ParamType): + return ty + + if ty is str or ty is None: + return STRING + + if ty is int: + return INT + + if ty is float: + return FLOAT + + if ty is bool: + return BOOL + + if guessed_type: + return STRING + + if __debug__: + try: + if issubclass(ty, ParamType): + raise AssertionError( + f"Attempted to use an uninstantiated parameter type ({ty})." + ) + except TypeError: + # ty is an instance (correct), so issubclass fails. + pass + + return FuncParamType(ty) + + +#: A dummy parameter type that just does nothing. From a user's +#: perspective this appears to just be the same as `STRING` but +#: internally no string conversion takes place if the input was bytes. +#: This is usually useful when working with file paths as they can +#: appear in bytes and unicode. +#: +#: For path related uses the :class:`Path` type is a better choice but +#: there are situations where an unprocessed type is useful which is why +#: it is is provided. +#: +#: .. versionadded:: 4.0 +UNPROCESSED = UnprocessedParamType() + +#: A unicode string parameter type which is the implicit default. This +#: can also be selected by using ``str`` as type. +STRING = StringParamType() + +#: An integer parameter. This can also be selected by using ``int`` as +#: type. +INT = IntParamType() + +#: A floating point value parameter. This can also be selected by using +#: ``float`` as type. +FLOAT = FloatParamType() + +#: A boolean parameter. This is the default for boolean flags. This can +#: also be selected by using ``bool`` as a type. +BOOL = BoolParamType() + +#: A UUID parameter. +UUID = UUIDParameterType() diff --git a/.venv/Lib/site-packages/click/utils.py b/.venv/Lib/site-packages/click/utils.py new file mode 100644 index 000000000..8283788ac --- /dev/null +++ b/.venv/Lib/site-packages/click/utils.py @@ -0,0 +1,580 @@ +import os +import re +import sys +import typing as t +from functools import update_wrapper +from types import ModuleType + +from ._compat import _default_text_stderr +from ._compat import _default_text_stdout +from ._compat import _find_binary_writer +from ._compat import auto_wrap_for_ansi +from ._compat import binary_streams +from ._compat import get_filesystem_encoding +from ._compat import open_stream +from ._compat import should_strip_ansi +from ._compat import strip_ansi +from ._compat import text_streams +from ._compat import WIN +from .globals import resolve_color_default + +if t.TYPE_CHECKING: + import typing_extensions as te + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + + +def _posixify(name: str) -> str: + return "-".join(name.split()).lower() + + +def safecall(func: F) -> F: + """Wraps a function so that it swallows exceptions.""" + + def wrapper(*args, **kwargs): # type: ignore + try: + return func(*args, **kwargs) + except Exception: + pass + + return update_wrapper(t.cast(F, wrapper), func) + + +def make_str(value: t.Any) -> str: + """Converts a value into a valid string.""" + if isinstance(value, bytes): + try: + return value.decode(get_filesystem_encoding()) + except UnicodeError: + return value.decode("utf-8", "replace") + return str(value) + + +def make_default_short_help(help: str, max_length: int = 45) -> str: + """Returns a condensed version of help string.""" + # Consider only the first paragraph. + paragraph_end = help.find("\n\n") + + if paragraph_end != -1: + help = help[:paragraph_end] + + # Collapse newlines, tabs, and spaces. + words = help.split() + + if not words: + return "" + + # The first paragraph started with a "no rewrap" marker, ignore it. + if words[0] == "\b": + words = words[1:] + + total_length = 0 + last_index = len(words) - 1 + + for i, word in enumerate(words): + total_length += len(word) + (i > 0) + + if total_length > max_length: # too long, truncate + break + + if word[-1] == ".": # sentence end, truncate without "..." + return " ".join(words[: i + 1]) + + if total_length == max_length and i != last_index: + break # not at sentence end, truncate with "..." + else: + return " ".join(words) # no truncation needed + + # Account for the length of the suffix. + total_length += len("...") + + # remove words until the length is short enough + while i > 0: + total_length -= len(words[i]) + (i > 0) + + if total_length <= max_length: + break + + i -= 1 + + return " ".join(words[:i]) + "..." + + +class LazyFile: + """A lazy file works like a regular file but it does not fully open + the file but it does perform some basic checks early to see if the + filename parameter does make sense. This is useful for safely opening + files for writing. + """ + + def __init__( + self, + filename: str, + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", + atomic: bool = False, + ): + self.name = filename + self.mode = mode + self.encoding = encoding + self.errors = errors + self.atomic = atomic + self._f: t.Optional[t.IO] + + if filename == "-": + self._f, self.should_close = open_stream(filename, mode, encoding, errors) + else: + if "r" in mode: + # Open and close the file in case we're opening it for + # reading so that we can catch at least some errors in + # some cases early. + open(filename, mode).close() + self._f = None + self.should_close = True + + def __getattr__(self, name: str) -> t.Any: + return getattr(self.open(), name) + + def __repr__(self) -> str: + if self._f is not None: + return repr(self._f) + return f"" + + def open(self) -> t.IO: + """Opens the file if it's not yet open. This call might fail with + a :exc:`FileError`. Not handling this error will produce an error + that Click shows. + """ + if self._f is not None: + return self._f + try: + rv, self.should_close = open_stream( + self.name, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + except OSError as e: # noqa: E402 + from .exceptions import FileError + + raise FileError(self.name, hint=e.strerror) from e + self._f = rv + return rv + + def close(self) -> None: + """Closes the underlying file, no matter what.""" + if self._f is not None: + self._f.close() + + def close_intelligently(self) -> None: + """This function only closes the file if it was opened by the lazy + file wrapper. For instance this will never close stdin. + """ + if self.should_close: + self.close() + + def __enter__(self) -> "LazyFile": + return self + + def __exit__(self, exc_type, exc_value, tb): # type: ignore + self.close_intelligently() + + def __iter__(self) -> t.Iterator[t.AnyStr]: + self.open() + return iter(self._f) # type: ignore + + +class KeepOpenFile: + def __init__(self, file: t.IO) -> None: + self._file = file + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._file, name) + + def __enter__(self) -> "KeepOpenFile": + return self + + def __exit__(self, exc_type, exc_value, tb): # type: ignore + pass + + def __repr__(self) -> str: + return repr(self._file) + + def __iter__(self) -> t.Iterator[t.AnyStr]: + return iter(self._file) + + +def echo( + message: t.Optional[t.Any] = None, + file: t.Optional[t.IO[t.Any]] = None, + nl: bool = True, + err: bool = False, + color: t.Optional[bool] = None, +) -> None: + """Print a message and newline to stdout or a file. This should be + used instead of :func:`print` because it provides better support + for different data, files, and environments. + + Compared to :func:`print`, this does the following: + + - Ensures that the output encoding is not misconfigured on Linux. + - Supports Unicode in the Windows console. + - Supports writing to binary outputs, and supports writing bytes + to text outputs. + - Supports colors and styles on Windows. + - Removes ANSI color and style codes if the output does not look + like an interactive terminal. + - Always flushes the output. + + :param message: The string or bytes to output. Other objects are + converted to strings. + :param file: The file to write to. Defaults to ``stdout``. + :param err: Write to ``stderr`` instead of ``stdout``. + :param nl: Print a newline after the message. Enabled by default. + :param color: Force showing or hiding colors and other styles. By + default Click will remove color if the output does not look like + an interactive terminal. + + .. versionchanged:: 6.0 + Support Unicode output on the Windows console. Click does not + modify ``sys.stdout``, so ``sys.stdout.write()`` and ``print()`` + will still not support Unicode. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + + .. versionadded:: 3.0 + Added the ``err`` parameter. + + .. versionchanged:: 2.0 + Support colors on Windows if colorama is installed. + """ + if file is None: + if err: + file = _default_text_stderr() + else: + file = _default_text_stdout() + + # Convert non bytes/text into the native string type. + if message is not None and not isinstance(message, (str, bytes, bytearray)): + out: t.Optional[t.Union[str, bytes]] = str(message) + else: + out = message + + if nl: + out = out or "" + if isinstance(out, str): + out += "\n" + else: + out += b"\n" + + if not out: + file.flush() + return + + # If there is a message and the value looks like bytes, we manually + # need to find the binary stream and write the message in there. + # This is done separately so that most stream types will work as you + # would expect. Eg: you can write to StringIO for other cases. + if isinstance(out, (bytes, bytearray)): + binary_file = _find_binary_writer(file) + + if binary_file is not None: + file.flush() + binary_file.write(out) + binary_file.flush() + return + + # ANSI style code support. For no message or bytes, nothing happens. + # When outputting to a file instead of a terminal, strip codes. + else: + color = resolve_color_default(color) + + if should_strip_ansi(file, color): + out = strip_ansi(out) + elif WIN: + if auto_wrap_for_ansi is not None: + file = auto_wrap_for_ansi(file) # type: ignore + elif not color: + out = strip_ansi(out) + + file.write(out) # type: ignore + file.flush() + + +def get_binary_stream(name: "te.Literal['stdin', 'stdout', 'stderr']") -> t.BinaryIO: + """Returns a system stream for byte processing. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + """ + opener = binary_streams.get(name) + if opener is None: + raise TypeError(f"Unknown standard stream '{name}'") + return opener() + + +def get_text_stream( + name: "te.Literal['stdin', 'stdout', 'stderr']", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", +) -> t.TextIO: + """Returns a system stream for text processing. This usually returns + a wrapped stream around a binary stream returned from + :func:`get_binary_stream` but it also can take shortcuts for already + correctly configured streams. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + :param encoding: overrides the detected default encoding. + :param errors: overrides the default error mode. + """ + opener = text_streams.get(name) + if opener is None: + raise TypeError(f"Unknown standard stream '{name}'") + return opener(encoding, errors) + + +def open_file( + filename: str, + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", + lazy: bool = False, + atomic: bool = False, +) -> t.IO: + """Open a file, with extra behavior to handle ``'-'`` to indicate + a standard stream, lazy open on write, and atomic write. Similar to + the behavior of the :class:`~click.File` param type. + + If ``'-'`` is given to open ``stdout`` or ``stdin``, the stream is + wrapped so that using it in a context manager will not close it. + This makes it possible to use the function without accidentally + closing a standard stream: + + .. code-block:: python + + with open_file(filename) as f: + ... + + :param filename: The name of the file to open, or ``'-'`` for + ``stdin``/``stdout``. + :param mode: The mode in which to open the file. + :param encoding: The encoding to decode or encode a file opened in + text mode. + :param errors: The error handling mode. + :param lazy: Wait to open the file until it is accessed. For read + mode, the file is temporarily opened to raise access errors + early, then closed until it is read again. + :param atomic: Write to a temporary file and replace the given file + on close. + + .. versionadded:: 3.0 + """ + if lazy: + return t.cast(t.IO, LazyFile(filename, mode, encoding, errors, atomic=atomic)) + + f, should_close = open_stream(filename, mode, encoding, errors, atomic=atomic) + + if not should_close: + f = t.cast(t.IO, KeepOpenFile(f)) + + return f + + +def format_filename( + filename: t.Union[str, bytes, os.PathLike], shorten: bool = False +) -> str: + """Formats a filename for user display. The main purpose of this + function is to ensure that the filename can be displayed at all. This + will decode the filename to unicode if necessary in a way that it will + not fail. Optionally, it can shorten the filename to not include the + full path to the filename. + + :param filename: formats a filename for UI display. This will also convert + the filename into unicode without failing. + :param shorten: this optionally shortens the filename to strip of the + path that leads up to it. + """ + if shorten: + filename = os.path.basename(filename) + + return os.fsdecode(filename) + + +def get_app_dir(app_name: str, roaming: bool = True, force_posix: bool = False) -> str: + r"""Returns the config folder for the application. The default behavior + is to return whatever is most appropriate for the operating system. + + To give you an idea, for an app called ``"Foo Bar"``, something like + the following folders could be returned: + + Mac OS X: + ``~/Library/Application Support/Foo Bar`` + Mac OS X (POSIX): + ``~/.foo-bar`` + Unix: + ``~/.config/foo-bar`` + Unix (POSIX): + ``~/.foo-bar`` + Windows (roaming): + ``C:\Users\\AppData\Roaming\Foo Bar`` + Windows (not roaming): + ``C:\Users\\AppData\Local\Foo Bar`` + + .. versionadded:: 2.0 + + :param app_name: the application name. This should be properly capitalized + and can contain whitespace. + :param roaming: controls if the folder should be roaming or not on Windows. + Has no affect otherwise. + :param force_posix: if this is set to `True` then on any POSIX system the + folder will be stored in the home folder with a leading + dot instead of the XDG config home or darwin's + application support folder. + """ + if WIN: + key = "APPDATA" if roaming else "LOCALAPPDATA" + folder = os.environ.get(key) + if folder is None: + folder = os.path.expanduser("~") + return os.path.join(folder, app_name) + if force_posix: + return os.path.join(os.path.expanduser(f"~/.{_posixify(app_name)}")) + if sys.platform == "darwin": + return os.path.join( + os.path.expanduser("~/Library/Application Support"), app_name + ) + return os.path.join( + os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")), + _posixify(app_name), + ) + + +class PacifyFlushWrapper: + """This wrapper is used to catch and suppress BrokenPipeErrors resulting + from ``.flush()`` being called on broken pipe during the shutdown/final-GC + of the Python interpreter. Notably ``.flush()`` is always called on + ``sys.stdout`` and ``sys.stderr``. So as to have minimal impact on any + other cleanup code, and the case where the underlying file is not a broken + pipe, all calls and attributes are proxied. + """ + + def __init__(self, wrapped: t.IO) -> None: + self.wrapped = wrapped + + def flush(self) -> None: + try: + self.wrapped.flush() + except OSError as e: + import errno + + if e.errno != errno.EPIPE: + raise + + def __getattr__(self, attr: str) -> t.Any: + return getattr(self.wrapped, attr) + + +def _detect_program_name( + path: t.Optional[str] = None, _main: t.Optional[ModuleType] = None +) -> str: + """Determine the command used to run the program, for use in help + text. If a file or entry point was executed, the file name is + returned. If ``python -m`` was used to execute a module or package, + ``python -m name`` is returned. + + This doesn't try to be too precise, the goal is to give a concise + name for help text. Files are only shown as their name without the + path. ``python`` is only shown for modules, and the full path to + ``sys.executable`` is not shown. + + :param path: The Python file being executed. Python puts this in + ``sys.argv[0]``, which is used by default. + :param _main: The ``__main__`` module. This should only be passed + during internal testing. + + .. versionadded:: 8.0 + Based on command args detection in the Werkzeug reloader. + + :meta private: + """ + if _main is None: + _main = sys.modules["__main__"] + + if not path: + path = sys.argv[0] + + # The value of __package__ indicates how Python was called. It may + # not exist if a setuptools script is installed as an egg. It may be + # set incorrectly for entry points created with pip on Windows. + if getattr(_main, "__package__", None) is None or ( + os.name == "nt" + and _main.__package__ == "" + and not os.path.exists(path) + and os.path.exists(f"{path}.exe") + ): + # Executed a file, like "python app.py". + return os.path.basename(path) + + # Executed a module, like "python -m example". + # Rewritten by Python from "-m script" to "/path/to/script.py". + # Need to look at main module to determine how it was executed. + py_module = t.cast(str, _main.__package__) + name = os.path.splitext(os.path.basename(path))[0] + + # A submodule like "example.cli". + if name != "__main__": + py_module = f"{py_module}.{name}" + + return f"python -m {py_module.lstrip('.')}" + + +def _expand_args( + args: t.Iterable[str], + *, + user: bool = True, + env: bool = True, + glob_recursive: bool = True, +) -> t.List[str]: + """Simulate Unix shell expansion with Python functions. + + See :func:`glob.glob`, :func:`os.path.expanduser`, and + :func:`os.path.expandvars`. + + This is intended for use on Windows, where the shell does not do any + expansion. It may not exactly match what a Unix shell would do. + + :param args: List of command line arguments to expand. + :param user: Expand user home directory. + :param env: Expand environment variables. + :param glob_recursive: ``**`` matches directories recursively. + + .. versionchanged:: 8.1 + Invalid glob patterns are treated as empty expansions rather + than raising an error. + + .. versionadded:: 8.0 + + :meta private: + """ + from glob import glob + + out = [] + + for arg in args: + if user: + arg = os.path.expanduser(arg) + + if env: + arg = os.path.expandvars(arg) + + try: + matches = glob(arg, recursive=glob_recursive) + except re.error: + matches = [] + + if not matches: + out.append(arg) + else: + out.extend(matches) + + return out diff --git a/.venv/Lib/site-packages/colorama-0.4.6.dist-info/INSTALLER b/.venv/Lib/site-packages/colorama-0.4.6.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/.venv/Lib/site-packages/colorama-0.4.6.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/Lib/site-packages/colorama-0.4.6.dist-info/METADATA b/.venv/Lib/site-packages/colorama-0.4.6.dist-info/METADATA new file mode 100644 index 000000000..a1b5c5754 --- /dev/null +++ b/.venv/Lib/site-packages/colorama-0.4.6.dist-info/METADATA @@ -0,0 +1,441 @@ +Metadata-Version: 2.1 +Name: colorama +Version: 0.4.6 +Summary: Cross-platform colored terminal text. +Project-URL: Homepage, https://github.com/tartley/colorama +Author-email: Jonathan Hartley +License-File: LICENSE.txt +Keywords: ansi,color,colour,crossplatform,terminal,text,windows,xplatform +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Terminals +Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7 +Description-Content-Type: text/x-rst + +.. image:: https://img.shields.io/pypi/v/colorama.svg + :target: https://pypi.org/project/colorama/ + :alt: Latest Version + +.. image:: https://img.shields.io/pypi/pyversions/colorama.svg + :target: https://pypi.org/project/colorama/ + :alt: Supported Python versions + +.. image:: https://github.com/tartley/colorama/actions/workflows/test.yml/badge.svg + :target: https://github.com/tartley/colorama/actions/workflows/test.yml + :alt: Build Status + +Colorama +======== + +Makes ANSI escape character sequences (for producing colored terminal text and +cursor positioning) work under MS Windows. + +.. |donate| image:: https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif + :target: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2MZ9D2GMLYCUJ&item_name=Colorama¤cy_code=USD + :alt: Donate with Paypal + +`PyPI for releases `_ | +`Github for source `_ | +`Colorama for enterprise on Tidelift `_ + +If you find Colorama useful, please |donate| to the authors. Thank you! + +Installation +------------ + +Tested on CPython 2.7, 3.7, 3.8, 3.9 and 3.10 and Pypy 2.7 and 3.8. + +No requirements other than the standard library. + +.. code-block:: bash + + pip install colorama + # or + conda install -c anaconda colorama + +Description +----------- + +ANSI escape character sequences have long been used to produce colored terminal +text and cursor positioning on Unix and Macs. Colorama makes this work on +Windows, too, by wrapping ``stdout``, stripping ANSI sequences it finds (which +would appear as gobbledygook in the output), and converting them into the +appropriate win32 calls to modify the state of the terminal. On other platforms, +Colorama does nothing. + +This has the upshot of providing a simple cross-platform API for printing +colored terminal text from Python, and has the happy side-effect that existing +applications or libraries which use ANSI sequences to produce colored output on +Linux or Macs can now also work on Windows, simply by calling +``colorama.just_fix_windows_console()`` (since v0.4.6) or ``colorama.init()`` +(all versions, but may have other side-effects – see below). + +An alternative approach is to install ``ansi.sys`` on Windows machines, which +provides the same behaviour for all applications running in terminals. Colorama +is intended for situations where that isn't easy (e.g., maybe your app doesn't +have an installer.) + +Demo scripts in the source code repository print some colored text using +ANSI sequences. Compare their output under Gnome-terminal's built in ANSI +handling, versus on Windows Command-Prompt using Colorama: + +.. image:: https://github.com/tartley/colorama/raw/master/screenshots/ubuntu-demo.png + :width: 661 + :height: 357 + :alt: ANSI sequences on Ubuntu under gnome-terminal. + +.. image:: https://github.com/tartley/colorama/raw/master/screenshots/windows-demo.png + :width: 668 + :height: 325 + :alt: Same ANSI sequences on Windows, using Colorama. + +These screenshots show that, on Windows, Colorama does not support ANSI 'dim +text'; it looks the same as 'normal text'. + +Usage +----- + +Initialisation +.............. + +If the only thing you want from Colorama is to get ANSI escapes to work on +Windows, then run: + +.. code-block:: python + + from colorama import just_fix_windows_console + just_fix_windows_console() + +If you're on a recent version of Windows 10 or better, and your stdout/stderr +are pointing to a Windows console, then this will flip the magic configuration +switch to enable Windows' built-in ANSI support. + +If you're on an older version of Windows, and your stdout/stderr are pointing to +a Windows console, then this will wrap ``sys.stdout`` and/or ``sys.stderr`` in a +magic file object that intercepts ANSI escape sequences and issues the +appropriate Win32 calls to emulate them. + +In all other circumstances, it does nothing whatsoever. Basically the idea is +that this makes Windows act like Unix with respect to ANSI escape handling. + +It's safe to call this function multiple times. It's safe to call this function +on non-Windows platforms, but it won't do anything. It's safe to call this +function when one or both of your stdout/stderr are redirected to a file – it +won't do anything to those streams. + +Alternatively, you can use the older interface with more features (but also more +potential footguns): + +.. code-block:: python + + from colorama import init + init() + +This does the same thing as ``just_fix_windows_console``, except for the +following differences: + +- It's not safe to call ``init`` multiple times; you can end up with multiple + layers of wrapping and broken ANSI support. + +- Colorama will apply a heuristic to guess whether stdout/stderr support ANSI, + and if it thinks they don't, then it will wrap ``sys.stdout`` and + ``sys.stderr`` in a magic file object that strips out ANSI escape sequences + before printing them. This happens on all platforms, and can be convenient if + you want to write your code to emit ANSI escape sequences unconditionally, and + let Colorama decide whether they should actually be output. But note that + Colorama's heuristic is not particularly clever. + +- ``init`` also accepts explicit keyword args to enable/disable various + functionality – see below. + +To stop using Colorama before your program exits, simply call ``deinit()``. +This will restore ``stdout`` and ``stderr`` to their original values, so that +Colorama is disabled. To resume using Colorama again, call ``reinit()``; it is +cheaper than calling ``init()`` again (but does the same thing). + +Most users should depend on ``colorama >= 0.4.6``, and use +``just_fix_windows_console``. The old ``init`` interface will be supported +indefinitely for backwards compatibility, but we don't plan to fix any issues +with it, also for backwards compatibility. + +Colored Output +.............. + +Cross-platform printing of colored text can then be done using Colorama's +constant shorthand for ANSI escape sequences. These are deliberately +rudimentary, see below. + +.. code-block:: python + + from colorama import Fore, Back, Style + print(Fore.RED + 'some red text') + print(Back.GREEN + 'and with a green background') + print(Style.DIM + 'and in dim text') + print(Style.RESET_ALL) + print('back to normal now') + +...or simply by manually printing ANSI sequences from your own code: + +.. code-block:: python + + print('\033[31m' + 'some red text') + print('\033[39m') # and reset to default color + +...or, Colorama can be used in conjunction with existing ANSI libraries +such as the venerable `Termcolor `_ +the fabulous `Blessings `_, +or the incredible `_Rich `_. + +If you wish Colorama's Fore, Back and Style constants were more capable, +then consider using one of the above highly capable libraries to generate +colors, etc, and use Colorama just for its primary purpose: to convert +those ANSI sequences to also work on Windows: + +SIMILARLY, do not send PRs adding the generation of new ANSI types to Colorama. +We are only interested in converting ANSI codes to win32 API calls, not +shortcuts like the above to generate ANSI characters. + +.. code-block:: python + + from colorama import just_fix_windows_console + from termcolor import colored + + # use Colorama to make Termcolor work on Windows too + just_fix_windows_console() + + # then use Termcolor for all colored text output + print(colored('Hello, World!', 'green', 'on_red')) + +Available formatting constants are:: + + Fore: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. + Back: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. + Style: DIM, NORMAL, BRIGHT, RESET_ALL + +``Style.RESET_ALL`` resets foreground, background, and brightness. Colorama will +perform this reset automatically on program exit. + +These are fairly well supported, but not part of the standard:: + + Fore: LIGHTBLACK_EX, LIGHTRED_EX, LIGHTGREEN_EX, LIGHTYELLOW_EX, LIGHTBLUE_EX, LIGHTMAGENTA_EX, LIGHTCYAN_EX, LIGHTWHITE_EX + Back: LIGHTBLACK_EX, LIGHTRED_EX, LIGHTGREEN_EX, LIGHTYELLOW_EX, LIGHTBLUE_EX, LIGHTMAGENTA_EX, LIGHTCYAN_EX, LIGHTWHITE_EX + +Cursor Positioning +.................. + +ANSI codes to reposition the cursor are supported. See ``demos/demo06.py`` for +an example of how to generate them. + +Init Keyword Args +................. + +``init()`` accepts some ``**kwargs`` to override default behaviour. + +init(autoreset=False): + If you find yourself repeatedly sending reset sequences to turn off color + changes at the end of every print, then ``init(autoreset=True)`` will + automate that: + + .. code-block:: python + + from colorama import init + init(autoreset=True) + print(Fore.RED + 'some red text') + print('automatically back to default color again') + +init(strip=None): + Pass ``True`` or ``False`` to override whether ANSI codes should be + stripped from the output. The default behaviour is to strip if on Windows + or if output is redirected (not a tty). + +init(convert=None): + Pass ``True`` or ``False`` to override whether to convert ANSI codes in the + output into win32 calls. The default behaviour is to convert if on Windows + and output is to a tty (terminal). + +init(wrap=True): + On Windows, Colorama works by replacing ``sys.stdout`` and ``sys.stderr`` + with proxy objects, which override the ``.write()`` method to do their work. + If this wrapping causes you problems, then this can be disabled by passing + ``init(wrap=False)``. The default behaviour is to wrap if ``autoreset`` or + ``strip`` or ``convert`` are True. + + When wrapping is disabled, colored printing on non-Windows platforms will + continue to work as normal. To do cross-platform colored output, you can + use Colorama's ``AnsiToWin32`` proxy directly: + + .. code-block:: python + + import sys + from colorama import init, AnsiToWin32 + init(wrap=False) + stream = AnsiToWin32(sys.stderr).stream + + # Python 2 + print >>stream, Fore.BLUE + 'blue text on stderr' + + # Python 3 + print(Fore.BLUE + 'blue text on stderr', file=stream) + +Recognised ANSI Sequences +......................... + +ANSI sequences generally take the form:: + + ESC [ ; ... + +Where ```` is an integer, and ```` is a single letter. Zero or +more params are passed to a ````. If no params are passed, it is +generally synonymous with passing a single zero. No spaces exist in the +sequence; they have been inserted here simply to read more easily. + +The only ANSI sequences that Colorama converts into win32 calls are:: + + ESC [ 0 m # reset all (colors and brightness) + ESC [ 1 m # bright + ESC [ 2 m # dim (looks same as normal brightness) + ESC [ 22 m # normal brightness + + # FOREGROUND: + ESC [ 30 m # black + ESC [ 31 m # red + ESC [ 32 m # green + ESC [ 33 m # yellow + ESC [ 34 m # blue + ESC [ 35 m # magenta + ESC [ 36 m # cyan + ESC [ 37 m # white + ESC [ 39 m # reset + + # BACKGROUND + ESC [ 40 m # black + ESC [ 41 m # red + ESC [ 42 m # green + ESC [ 43 m # yellow + ESC [ 44 m # blue + ESC [ 45 m # magenta + ESC [ 46 m # cyan + ESC [ 47 m # white + ESC [ 49 m # reset + + # cursor positioning + ESC [ y;x H # position cursor at x across, y down + ESC [ y;x f # position cursor at x across, y down + ESC [ n A # move cursor n lines up + ESC [ n B # move cursor n lines down + ESC [ n C # move cursor n characters forward + ESC [ n D # move cursor n characters backward + + # clear the screen + ESC [ mode J # clear the screen + + # clear the line + ESC [ mode K # clear the line + +Multiple numeric params to the ``'m'`` command can be combined into a single +sequence:: + + ESC [ 36 ; 45 ; 1 m # bright cyan text on magenta background + +All other ANSI sequences of the form ``ESC [ ; ... `` +are silently stripped from the output on Windows. + +Any other form of ANSI sequence, such as single-character codes or alternative +initial characters, are not recognised or stripped. It would be cool to add +them though. Let me know if it would be useful for you, via the Issues on +GitHub. + +Status & Known Problems +----------------------- + +I've personally only tested it on Windows XP (CMD, Console2), Ubuntu +(gnome-terminal, xterm), and OS X. + +Some valid ANSI sequences aren't recognised. + +If you're hacking on the code, see `README-hacking.md`_. ESPECIALLY, see the +explanation there of why we do not want PRs that allow Colorama to generate new +types of ANSI codes. + +See outstanding issues and wish-list: +https://github.com/tartley/colorama/issues + +If anything doesn't work for you, or doesn't do what you expected or hoped for, +I'd love to hear about it on that issues list, would be delighted by patches, +and would be happy to grant commit access to anyone who submits a working patch +or two. + +.. _README-hacking.md: README-hacking.md + +License +------- + +Copyright Jonathan Hartley & Arnon Yaari, 2013-2020. BSD 3-Clause license; see +LICENSE file. + +Professional support +-------------------- + +.. |tideliftlogo| image:: https://cdn2.hubspot.net/hubfs/4008838/website/logos/logos_for_download/Tidelift_primary-shorthand-logo.png + :alt: Tidelift + :target: https://tidelift.com/subscription/pkg/pypi-colorama?utm_source=pypi-colorama&utm_medium=referral&utm_campaign=readme + +.. list-table:: + :widths: 10 100 + + * - |tideliftlogo| + - Professional support for colorama is available as part of the + `Tidelift Subscription`_. + Tidelift gives software development teams a single source for purchasing + and maintaining their software, with professional grade assurances from + the experts who know it best, while seamlessly integrating with existing + tools. + +.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-colorama?utm_source=pypi-colorama&utm_medium=referral&utm_campaign=readme + +Thanks +------ + +See the CHANGELOG for more thanks! + +* Marc Schlaich (schlamar) for a ``setup.py`` fix for Python2.5. +* Marc Abramowitz, reported & fixed a crash on exit with closed ``stdout``, + providing a solution to issue #7's setuptools/distutils debate, + and other fixes. +* User 'eryksun', for guidance on correctly instantiating ``ctypes.windll``. +* Matthew McCormick for politely pointing out a longstanding crash on non-Win. +* Ben Hoyt, for a magnificent fix under 64-bit Windows. +* Jesse at Empty Square for submitting a fix for examples in the README. +* User 'jamessp', an observant documentation fix for cursor positioning. +* User 'vaal1239', Dave Mckee & Lackner Kristof for a tiny but much-needed Win7 + fix. +* Julien Stuyck, for wisely suggesting Python3 compatible updates to README. +* Daniel Griffith for multiple fabulous patches. +* Oscar Lesta for a valuable fix to stop ANSI chars being sent to non-tty + output. +* Roger Binns, for many suggestions, valuable feedback, & bug reports. +* Tim Golden for thought and much appreciated feedback on the initial idea. +* User 'Zearin' for updates to the README file. +* John Szakmeister for adding support for light colors +* Charles Merriam for adding documentation to demos +* Jurko for a fix on 64-bit Windows CPython2.5 w/o ctypes +* Florian Bruhin for a fix when stdout or stderr are None +* Thomas Weininger for fixing ValueError on Windows +* Remi Rampin for better Github integration and fixes to the README file +* Simeon Visser for closing a file handle using 'with' and updating classifiers + to include Python 3.3 and 3.4 +* Andy Neff for fixing RESET of LIGHT_EX colors. +* Jonathan Hartley for the initial idea and implementation. diff --git a/.venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD b/.venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD new file mode 100644 index 000000000..bafc005f2 --- /dev/null +++ b/.venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD @@ -0,0 +1,31 @@ +colorama-0.4.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +colorama-0.4.6.dist-info/METADATA,sha256=e67SnrUMOym9sz_4TjF3vxvAV4T3aF7NyqRHHH3YEMw,17158 +colorama-0.4.6.dist-info/RECORD,, +colorama-0.4.6.dist-info/WHEEL,sha256=cdcF4Fbd0FPtw2EMIOwH-3rSOTUdTCeOSXRMD1iLUb8,105 +colorama-0.4.6.dist-info/licenses/LICENSE.txt,sha256=ysNcAmhuXQSlpxQL-zs25zrtSWZW6JEQLkKIhteTAxg,1491 +colorama/__init__.py,sha256=wePQA4U20tKgYARySLEC047ucNX-g8pRLpYBuiHlLb8,266 +colorama/__pycache__/__init__.cpython-311.pyc,, +colorama/__pycache__/ansi.cpython-311.pyc,, +colorama/__pycache__/ansitowin32.cpython-311.pyc,, +colorama/__pycache__/initialise.cpython-311.pyc,, +colorama/__pycache__/win32.cpython-311.pyc,, +colorama/__pycache__/winterm.cpython-311.pyc,, +colorama/ansi.py,sha256=Top4EeEuaQdBWdteKMEcGOTeKeF19Q-Wo_6_Cj5kOzQ,2522 +colorama/ansitowin32.py,sha256=vPNYa3OZbxjbuFyaVo0Tmhmy1FZ1lKMWCnT7odXpItk,11128 +colorama/initialise.py,sha256=-hIny86ClXo39ixh5iSCfUIa2f_h_bgKRDW7gqs-KLU,3325 +colorama/tests/__init__.py,sha256=MkgPAEzGQd-Rq0w0PZXSX2LadRWhUECcisJY8lSrm4Q,75 +colorama/tests/__pycache__/__init__.cpython-311.pyc,, +colorama/tests/__pycache__/ansi_test.cpython-311.pyc,, +colorama/tests/__pycache__/ansitowin32_test.cpython-311.pyc,, +colorama/tests/__pycache__/initialise_test.cpython-311.pyc,, +colorama/tests/__pycache__/isatty_test.cpython-311.pyc,, +colorama/tests/__pycache__/utils.cpython-311.pyc,, +colorama/tests/__pycache__/winterm_test.cpython-311.pyc,, +colorama/tests/ansi_test.py,sha256=FeViDrUINIZcr505PAxvU4AjXz1asEiALs9GXMhwRaE,2839 +colorama/tests/ansitowin32_test.py,sha256=RN7AIhMJ5EqDsYaCjVo-o4u8JzDD4ukJbmevWKS70rY,10678 +colorama/tests/initialise_test.py,sha256=BbPy-XfyHwJ6zKozuQOvNvQZzsx9vdb_0bYXn7hsBTc,6741 +colorama/tests/isatty_test.py,sha256=Pg26LRpv0yQDB5Ac-sxgVXG7hsA1NYvapFgApZfYzZg,1866 +colorama/tests/utils.py,sha256=1IIRylG39z5-dzq09R_ngufxyPZxgldNbrxKxUGwGKE,1079 +colorama/tests/winterm_test.py,sha256=qoWFPEjym5gm2RuMwpf3pOis3a5r_PJZFCzK254JL8A,3709 +colorama/win32.py,sha256=YQOKwMTwtGBbsY4dL5HYTvwTeP9wIQra5MvPNddpxZs,6181 +colorama/winterm.py,sha256=XCQFDHjPi6AHYNdZwy0tA02H-Jh48Jp-HvCjeLeLp3U,7134 diff --git a/.venv/Lib/site-packages/colorama-0.4.6.dist-info/WHEEL b/.venv/Lib/site-packages/colorama-0.4.6.dist-info/WHEEL new file mode 100644 index 000000000..d79189fda --- /dev/null +++ b/.venv/Lib/site-packages/colorama-0.4.6.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.11.1 +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any diff --git a/.venv/Lib/site-packages/colorama-0.4.6.dist-info/licenses/LICENSE.txt b/.venv/Lib/site-packages/colorama-0.4.6.dist-info/licenses/LICENSE.txt new file mode 100644 index 000000000..3105888ec --- /dev/null +++ b/.venv/Lib/site-packages/colorama-0.4.6.dist-info/licenses/LICENSE.txt @@ -0,0 +1,27 @@ +Copyright (c) 2010 Jonathan Hartley +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holders, nor those of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/.venv/Lib/site-packages/colorama/__init__.py b/.venv/Lib/site-packages/colorama/__init__.py new file mode 100644 index 000000000..383101cdb --- /dev/null +++ b/.venv/Lib/site-packages/colorama/__init__.py @@ -0,0 +1,7 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +from .initialise import init, deinit, reinit, colorama_text, just_fix_windows_console +from .ansi import Fore, Back, Style, Cursor +from .ansitowin32 import AnsiToWin32 + +__version__ = '0.4.6' + diff --git a/.venv/Lib/site-packages/colorama/__pycache__/__init__.cpython-311.pyc b/.venv/Lib/site-packages/colorama/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3e7b3be2a44f2f088253fabea0ebc213488cc1d2 GIT binary patch literal 578 zcma)2yJ{RU6qR-~vya(z5faD;q#44ljU7@16L1VB1mk9H3}UdX-I0T0JqBrJ{iysG z`G6E5f3u}gWk{7S;3l}rRcsfj66td83*B>czm7%&1n1Y6<7$8r`W}>eGc6E>Tbf5P1fWkniCo0!NI)s?eQI$?nk^KNB zRHT7OBb$&_;@-P^Kbl)*9oL*S;=BpZKefJLC-R(~NmJP~&*s*6t3*Kp*|AOp@{Z3> zLpp6PlnB{&>%4UZ4*8bxa^D_Gv$1}eu1#J|UhfqvVGzkASJDfYfDT6@q!F?RU4TG1 zymh^p_anq5xjc6A*l8?i*;seOKNZFn!g*;8W8cs%l+fML_M7qm2z>dT&*Y4kwiae; zTQ?Wwj^h4wd?;q)t-2oXw~cimr<^Q=S(LkSR>FKSuHjGoqwwY9HdYyn${Cx~7k9l) vZL3y^x9%y>#dUfE@H4>}-=Kr#|JgNqx%`)1qZiA+?PlfKRUWT<0+hc2`VXpM literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/colorama/__pycache__/ansi.cpython-311.pyc b/.venv/Lib/site-packages/colorama/__pycache__/ansi.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9bffc9f74743829a65d8be343fd1017c0a998624 GIT binary patch literal 4576 zcmc&%&2JmW6`%d!Hz`u2KSbGW=-8>t*rJ>SC}Jh3K~a>fnxYI*vYL(D&5E;;Xj7y* zyK-Vd0eJ910(_7Q2iDO=Yd3~3`BOx|2Vnr8dg6_STp;kN@6D2wNI5Nv*60xP+nM*~ zH>7p zW7Km`(%kU$!qX#@2||7M2=$xZrwSp@p*ltL30(km!6Q1q(1k$PXZm{P1%xgPy2ue- zQ0V$W7d@g2$;1pih0UM0O(0qy$bvnxFvvnZvIxlhJ+gipE0E;z^_qWnxnw0)s&uVv zCYH>K$qd`H66t(lGErPMm{GJ%mMB&!2<>WOm6a-Xsj>u;a+L`Y=vPV=qim)81=Ac! zEZg?#$ndaPNqtkgU0OA1$w*b%(lGXhab4ZCipHv`S^y=!+?3!I=C8NBMx?@)EEaXay z3s%WChgOZ^ZDYx_7KA&D6=T?_Sf$kJT^_=Hbi1mf6D@}P3_{&M2~Z<11AX7ewr3y2 zAI7(?>=f#O#IBmy2NmgZf(!!Tgp1JVc7k)r4T49taa^l(j=nB`{8>@qW0ESm4GJbogPaER*F^-`r|>-u`M1l#gSm4iKKtFCjut~=Qi+Cg3a=f(aGrQh1PQ|RAbid!aUh+Lz=YU~dqu$0t8OLIx&A*X8Wnw7pD_=GP!+ z;+{Un7KRtQjPN9*|sNG$m{SRax;d*Zc z$0#(VD;>4pJ^M4DIsB@_7agP_1yYa->Bj}B$E|s(NAppy=BGX_K>b>f2DA_jYJD`M zg=wD_p<%6`MzkpH*J3mZ_ZQ<{yp-`OGaJ8zEgJ73BoNLZypMqSrGXx5U=C@ZuNxY| zmk7wQ#!ZAjAm|8RA>f-M|Lj=L-Eh}v4%o|;nd}&MP0VDodG7uqo6Aklb9FQ~m*t+R z^h7p4o91ffi*%m5=C4l9X1Qx7TgcAxP;PSK>a18o&;FhVL>HFAj-wMxVz*D|oTafJ zY)zfZVlOOut*s8!xFzV}n&u#$r`WVMBgbAqst&a!MvvKsX@OHcgK8~Z0 zyVFe-?#f1qvT%&A_SG&`T8u_cgv=erSP-5fqwuRP)R=N=?x0^=nV3jD`S&W z+?}7EnM&ulPf%V@=W@Ni*??6T0>+(%L3)UPk^b8F9zbR<5_MXWHTXH?!Abd~#L%K- zlzViYR*SmM+|Xxz2>543d_Ic5F5+K-_#o%*>f$Z4Xgi-9X6!5KM-BU`GAsuXRKqpQ5geoU0 zL)-)xs+y=G_2yu8$T8sv)lAgDH9KJ!9N(@mFhb=A@U#zeJTMb>19O1kEpIWrRjB>I z2srrH%ET&yvjNUtf^+ih7~`q<44aOA#sc)1Rhu^~1%@M{pq=&mCoiaWtQ(WB1O?Ts z{TTa)Mm#39P6+$Y1O?wk*%uWflY%4#!e>?M$v}8q5JRdBP6i^uh)B-JogRZ~xfBTV z!Jt|Rzy4^zCkv81sj;g;L-yjyDLA>o2ns`yHHZ%(ZmlSRQFIw|_2Q9+z}P~nDxSCZTBmI%(> zB~4GBbNeN@<|EUxr`zqHl;I_@%I}s%e^`q8MIkJ^K>(MpxThkb+aC-PQhr$$181gX z0q#NBxc$&nc29|skUJ#E=OVnj^O6{lg)UELxBJq$06Zxmxp^Tdob}5B@0KI($h1gk z4Mf5h1yL46cOWdu{_v#GL+U4KSA(ojaCrS>9T8lNjWIqr(@M+$SJ=s<@XQ! zs?%%QqC0y7$dHN8$h7e zvx1CWFFMJ!=z<^B6!wP%30u3}Vk6d6`h3}j!2jxE{wb;%+Ddf*=9ov0`g!^K)r6dM zbf+BMimh900>mWc2`#8{Xl?oGegK$@)ai`OUEN5aTVD7MlB?+5n^%GbDC443;c^o)J zMnWHna&umrRcy_rQbHaGAG_fMq@?2`q1Ru)Y6Zp@)PG2E-~n^81o@$?RWmW3ce2tn z$--q>FHCU@G@5Z1%8=aB0|*KA6F9bUU<;OQtxLAn1vzPJPubd)+)*k{6Wl~z<1gT( z@HJ*xo|Scqah{%EWJGt2{dQ}Nl`U{vwwy;=q)anXbrCKXSTNI!2;svRV+X}LPw$>J zz`!;Xy0tN8JtJ4=XfjMYBbr#|6^1vCF_)Oj##fk2tj9E}R=@npz(McvBff)2$Hs>S z$A>*OZRi^!l4=D591tU6)hJz&)C$l>;`V&L?71L0E7!a)-keb?J#eHQF2&K7 zxcHItL95caAC8AR|9R}6URMTQg(KatW?s%1%=Y!^=5;rZ#E*dKscW0x`-A=0_bc4G zr(al^n$`@%+E?d6+Sxe&-28JHBh)^9`c$fgXaCabwK1RAD!lc^Ph2d(0wYVc;ALo9 ztOcZ}sM?ZVp*_todJUK|&^`h)oa>`IhS714N$V2JWH2HLyoiHFtvKNiP79i(HJumt zKz)JA?}v(Fv1&B-VpBxVF^@H|qL>=f&ehlVDxCZ27Z#>=?d=N1u?Z#9mUY@W>?&ZU^4<7v?6MUYJ-Rh;xhS)h-}|s$Y|8eI2tn%0sc#W4q%S{Weg^> zEyEzFFqt>tSr%}tc{99M4p>a)7Z95TfPEgZSzuw!s3(S*Jl_C z8W~G<#$Yvr6ajp0gv+;1B>dBY#s$lhn*a)9Ux@ro=c!@f4Tbh`!cv4c z7U8Y@Du|NVa#1qI$P*l239yRi09Nx=03Ccaz#85Gu$Hd@xQed@=;TchKReY*oED5n zAjt3CKJ&LE96c0@289qr02m$9;5HZSk`TAs9SOVP9zJqOf~YqT3}UPuh`PO_V~5<6 z=lmi>*n$@IO2Qk{0>rwK7BtJ}1UFiF2*Sg>J1_;&u^gS2Njwg*GQ{KZl`P3@JnDv9 zLJ%^`5yBpc9NkmXVTj>@i%E#oB`uDgX=eAYIsIx^*Z$q7`Pd%MMo-tP{>?Mq%@ePA z4Etwl5&K%#tFK#M1B?}_Mu#V9UqDyk5XZiI@_QKi#Zf@aqz}Di-F+A>6vmOzGN%KK zYy*nfqU(9~0&y*~=9oEBC1VhfErkwY)`F%eVa;LnzeO#r;Z@)~P#LoY43in>ptIIj zn6N2lnqp>-iB`)P*Jex1TBv2SHt_6}|MO(#j7>Qv(x}HIDsvR{zeQZxW0r^^X5*OI zikNZE9IJ>LVs^MP#*82(v_quC40EPfMTCvnXANYMLnRVp5;}*NYtIzT2Z0tw%%te! z64{-tgrD>16iAtd*u{sDJ}DTJc#NZ}AuNCPUr;APXViIllyEUJhIod^izPZRh-Oih+P5EC{?WPe8)%g-KwpXjU5y|4g0EXwZ4u zF~CSIFmk{-HMBxB%i(lwJx$j)sw?kFs?_3SnPbN(7`r;Lt3dX%r zS-a=ng*&0UA&5LP2BW<$UE6r0_1)HFZCk3gE#4pRfBMKlJX#&tY`X^1wNAvu`_Zx0 zfn$5TVN0S_X*>Kcy$3!uBzq61dJikMRtPArznNUlBQ)1T_; zkK58sJxbFNW!Dj<_ek6UTywSYz3IC3N?q^b^NCn|DD7$jo+}XJjPFm^Z&2#DFLuQb zr0IJ$yO-B&Sz5Ctxn^5x%{DSO#kX(0*?iA=w@F#ui(-hwpM+}niMh_(#C+1kc|FEY zx>$e(p$P^a#13h*SG_(*tKfv#kv)jlJNi|^RMGHxh8ze_L62VslMC554SteA^3SmJc{GJgg zL&L}~I-zhRy!oW2{qAVcFGKDo1TJYh9K>WzgbYc4kh%+hFd$!X2Ll)Kr06Jj!`J}6 zK?2AIB(xxVGmXhGw>EFaR1T&px;&H(h?WaSqljImpMh0M=OWWVo+M;u8ua5vhq!__ zVHyCY*)>c}-L;tF*s~x*xa`=oIDYqa#kQw(8iT`=Xvte(p$h}pd9%1lKaGLw^#Mjk z|CTLz`>t=7pUzCNKV%EqQ-4>`-jbuIpS0w?+?1h+3iX96pn`UkloBcw^R=nqlrvk- zQ}0zkg?c0z`=g{S;YCk{`lc07p>0d3P~WuzDzt4073%v}K!vs~p+ddn3aHSwB~++) zT>%x^wuB0eQdU5Pwk@GT`)dVMFwsX!2^EY9NGVT+j2QYPh&CF&x_x>5;@K%9j2S&0 zOf-^G{<#HosD_oHgPwb(bf}J%p+m>T3izQ~rqKZ#q<^zDUxOp6X=OOVd><(*;E3v4 z89Er&t&|ScwlZ{ZUc6E|RNu06_T}yc4JvP;+_@G7Jx|*bz135pI#D2<@>FQs5-L<9 zRzQWeEulj7VFgrZ+Y%~N7gj)pwk@GTHDLu*XxkDhR1a1_g|;oBLPy04s8Ee5p;F#L z(Viw2O0OB^Efj5EUcbudX?Y7(o(|QpGIYvYsPc5Ej+LQP-a?h9L$yq!bDNd*5-M+@ z%2T46hLj4Zl($disZdQTp;F#Dm8U{At%OP|lPzCI(~wHQbQ=qtZltBR1Yf%Rh%Lqyend}wTF+~*w`QSD?#?Sp_`we%l9bl~8)3R7fQmKHJeQjLR$ zj;NN=qsNbUM??%*RdfG{ci^yUg2-MF(afpF<3oe0`M~j^p;6WH%FxKj(UYpFf8-lO zs`ZHXz|iQpS2Yd1;vH4ZCl4MPA5u-w^cB@icu=cG@R@|BZ|Ia-NiKmPUT8Q%7%!^{ zPI~}ebJ<(JF@#qRa+Q5x9*qyiD~%Rm04_z0pHTHohPm%aM^1LP-T=&Y-LRI@r&v;OwkRL3r5!|sd`s(y!6?%TU= z?ft0h!4_p*f5r^8m?mzzUUl1gtLon6yWdjQ?$21U+6L7{&FxrU!PKt4UVXdaRx>oe zs<`)MDzTcwYVQ3@H)Hos-94?e?#@(Ub#+N=2Ugc$wc~c@t?rL(4;)I{i=D2h|!YeIGTZwt10t7b5CQ+BaZzBUa~FoK@U=Gpn(>iB>D_t(i4g z)l4XN+-tbo{L$qHS0Bns*GQ%XF|7pCe*4m`*hi-xoPM}N={T5Kix_vgd)g4Qj$k_P zb>8j%we44qPwN!VXl6ZNG7O^I33|gl>s{`na}Pof$Cb{PG8+)nK`>qScHQm!bz|y< zL!a(YHolzcL{wL~n>>iwNH96xXCLxP*Wt`2#B>9OzCY=r%~;)o)dgL&1*^A~wBCl* z+p)T!i+Zto2UZt!(Q{b66RL~5Xcr=$FKPb*R`15@f-c&F)qS)YyJ#;~?IVq53R>NK$@*-;J#@~WzoXddv$zUOvjBv@738Y5b>RG3uuV&6z6{S%Ysu;^ zBqwvZNLkBzZb77ZDmX2jBY98pn@}Nc1yHbfhRtSb^=6dN`vta}1E3kt-LPh4Z(FFl z*-TE-T+K4KZi!o$*pcMAQe2lpj>lZhwUK46b&11eWv)HNwJTgZG|tr~Id_V4!^#^P z&z5EVxBAt*|okuIKb={u7K4}S&ir7(c3H_R|b`&JbG(RYq6 z3?%B3Tt|xQP;v*ZLN{RtY)uT_I-F|XNzQd$`Tq3HZzZ`cDQ=6BJFwHXl6HBZbsrTm zJRi9y-8TxESJ*zt!U6`9fXdQRJltks;V7TXUD?1MWL_J^#ghab+WO~w02d$9iqpX7 ztO=Hwm}d=tSZXm9ZZ>4K?M75R;7Mf_r0_}KXTT7cXAReme$}&N8nl<1o?F$k2u-9#0FZv>m{m^Lt>JJkJJv2a z)+S6z$A*++L)?^htxmZ%EW3J^Ts@0&(zPSy+JVLsHempOHImh>KW_R_(|gS~o8NvZ zJ~ZD8gKL>#qCtMooTKmKA7TK7N&n3`%&z@t2eJITn`*+S7UrQ zJ`9_AmTfIdww47xF??^}zUj`PyN8mtohjQ+C3k3}5DjOppuUn(cnwa#h#F$X3j`UUNh-jm5Qskd{p5>oFphbHt!Du}zb^+m+^JV$?KwD)|t6_xT#sVK~ z!S#nEaSj;DN>Z)V>R{mG=HphAuq8++bPenn&|n#21Ko%P4GZd>ejMBjiKw z7*s>gR+WwFL)I_teYnJVIV$d(*{oN}LT&Hq3r4`>Nc(zd^M41r(ry6%0e^Fh(sT-r zkG;3Y7HfZU;?{}9H-7qR;??(i7v6Yp=gpl9JMa6o7J5k3^GkNmXC!K43CrchHUZC} zV(VC$*nZ*qDzRln)=9o#Flg>myaA69-@_L}j&e>6H&T5~;rte9YzL4N&M~FwSi=90 zW1rT3a^g29K7HfwUwuf0^AOJQ51PP1ghKdHjV~PziQfV$s>$0wFbJFG&GIyCj{=t) zg{5TDwK-${E;JK=fZ&G!ifqn2RLwL!yLlP9(i2Q{IzMooqUl0_ZxGa-E6~KU(FQpZdY3>zfknyIbbBJYKyv(f(e`yyXis z;);@MNEeMKpJsjzlw)x@t;k2tcVNqNiaFCkE4p(l9s~a&4HF_^Xx5CJS5tALt zBQXQSvzHi{{&@q!O4w=!b@rR47@L;{ znSt9 z71&m#R%I*v{P}4~&TY&hV;_gTY9=9vYR3(VKJwXx2~Wj!_`vnpf(@(eWtF{BeuLE< zG?}T_8;blK8uLSv2w{U}Bqrb47vGm&y*9&Gsx}fZZ-$M~3xlcVZpDd5+TEUVZ@uqI zxp&PUf{$hr$8Pq`50aC_@x<|)d*=rqwX`h`-W^q1_9R>Oq+0gCkgjW-A6#fx>O6@K z0NU|1Q32ij$6SrqtNhx z*;~Zjj^!u*AHXAurt(HGeDD=r;Zy}CFQ!7%N8&h`(yTZ|V4k(aEc$(_S<`$fW=@nf zOMFq@kT+!S*bjG3tM~_K^y@-O*KzOro*!MGpr!C!HyO{4#+_P zj7NUP_D9%&PTMq}Pc49iq}uJVh6T%lYr%58FVUWm5^_SmwK3`Jjt{2Scm2HYr+q)!cWWO^^x}sX8q$vX_t(F3 zHGVbiY+ZJ?FFD&2V@anc<@78bTXOa&&YpBj*K$kGQcKUGlx*ouwe-#p!>1RGtqcC^ zR}zCtLl+#68rLp2dX^eJiyilC?|PDrJ5r51l*S!TA!QJ+)J6%s5G^=jz>G6bo(E7k zdn`Y{Db#z-=;yv}BRRtu5Gu(OVr604mt>0TP`1s01KHZRYmixJTCz1IZOtiLGi)@~ z4#G5S03IFo)QMiC-j84a!5{$D03Xuglrjo?eZ}u!^)C^ilM_!PIEDZ-&*C=`V9G`O z9s-OgAM zfw{x!Rn1yWUvkyn)T+I6hcl)QGh}88!ON`8+?Qb}sM~0+&oC66Vy*a91O;^_Gh{v~ zsID^a$}kkTjpjDUx8?w6#IG?Z;2cPrf_A65pUp5j*j;6Y?Yk7X=?5A4Pc!gL6Auam zy5(po`{>vv-`Ir zXU@YmR&9ef>4n0c`O?;>eG0Qrd7&-6`tYla+h3^G9}Rwtsm10(}u34w6Tk{Mbp3yEGu=(i{uy<1T!n`N?w^F ziP@zk2P{ArI)PR7dY7FJzQ_*9OJr$%uAnXDH1QZ6E8w1sV5THQco8_*! zYJ;|?&hEUOpEomaX5RbW+uz0GQ3C1cH}C2Hh!OHvtavHZD;)j`3Xh0RbXp_}?w2l5 zUJosV^pGwTg>`X3q(m3D$bzIxK*M@MSGMSatVf`x=uw~%gRb%QaAsZIBD?V2!wOFe zsvZNbm>vfj4-rEO_QU*ij^qZuK<@k(6ljh*>gAGU&X;ePrHijG^Lctigs%Yk&<29? zYnVZ9Ed*K6sU|{}BE*jOM!;uH_R97tuSCc$thI;h@dR>^Ir1{G2fY?TvV_6@Z}OfE zvMJmo8#EWn&*Y+xT4v^I!Ls#o)jqBmj5&!7rd2A2?sfLpv0v3}W7D(?dbwmcsTFe* zSU1d)Uf!?@%jJ?)E*ehQ<#D3b5;Im!%Ql!3VTNVc1+7?g5|?e8nM+mMxWZVOJt2oE z^H=Y^{e#8pmcgvWS#8N&(iY1Vqcm5pvSnj&rl?tWrfwKZQAObh z?&43)rA5oMjj4*Zd`DX~ti|PWvCOn}?KQJx+Q4X9#&qSLGXauTjDlGLfl68twg`e2 zR?4hk83SZ@LnFLte6lH~yP_n;pDT&B zl75_PDcQD?ZF=v~zMAfmkQ6^A2TH6VHpH$3tw%>k7AQFRFr6b$qHhSlr*8-WZ9z@p z+M+|@5kZ~t(*0L$|LzH~J-dMJpkD0s^>|}}2a3l!?&=Qe&l8%@2@I8#g^?tXpw6)* z64WiX4LdTBt#1RVlYM!xDNpPxLl3XDluTR6e6E~-rkrmn7uw2&ruTLQqMQXjKH1Ft zGOpt#RB^u5ZP?Z$QWLCm{Tr;28m)y^h2ZAcfQ@5%NvFZyUr@Vmg*Bg369es%H(m<| z+I{}I0H!IIvNoPUFWHJ$B3v?%PuPW-_Wap41FIMO*)%z@iqFqiiJVvkwWF7C|Nn6n ze>N>*4|^lwmd5Ruj%#cFtoE7X*5KKJN`$m1ss!eokbnOI;=-FVTG28xVCO4EbJ?~s z8>W3bqm}Mu%Jyx8Wi+<><~*w!^SOj0K(iBlS1VRsGj{~*p5=sH%;DEz(5--9eKJr-Ix$&v-^yVMMR_sbUcBL!O z$PE2Jco5yb^}q7JP)O`0M32#ZCGlY3aipb8ww1}IGTAwOrlI14P%_F{xLqy7w)}*~ zkD7P52IK^QB>Ul{A3zE|WY`D-y>x%5zZT&4t<2LGmV!Y!$;FT~lo=|Td(ER*3POq# z)(w6)S?IeA*?JX-k1DAQo?Q=O+)5+bhz8Ikuxpf>?>fV=q<^1l(BdYY-a#J1!12zJ zew*yI^zFSa_uKn@cZAxT2tI)o{BaPBfE9fv?85o%`DgTVQtNZ*ELIDQF8HJEubbaT zp0Amo*64A-0Q1v+=?cfAMGQH>wxzryfdjwz`pgr7oy8N$AejI%pNlZOK1Zn(H5>fo zIzy?rsk+vQ+j1|LkHpK(g`8-~*zn>9uMBo>p<;Q~II>o?>;l9OC!+`UE#R7kY&`^0 zCty>Gx>eiWcqUJP^XMpvMtENyL-QQyRZ>m)+;49+UwP{QJHbW=#~;uAdg1BtALjpb zy_uYACFk17x%y8!a?`x0`OF*s>ipJ)v z8n_5zf}8k+en=?<7&>{EJc3fc^V)@Rdyw7aM{`_7-L{h)UPR{_TZjW2%K|T4fCxYg zSbJv!zky?qd!Z48JexK{nG2Au9|QRtJazJ1R2o^>=k_=J{dPlwlH5X==faQd>vvbhq$jDfMC>&+a@Z`pQ zV>kjy8M1X1NS$Z9P!Q9q03k_$kp20v7Gnd6ijpJJ@; z#-fv0LdECE;Us!v*R>M-3ox$Y4DXW*f5P>ArTlQctXGT1kJ$Ht1<&023lP`@r3WNl z=TC$)NVXY#yWwF9p}tS1Lv#upvqz$73Vu3Bz9-UiaDpC5q_E_ZX%dRH v>6vawqRB1+@})pRqkhXNk!Eplk0io$uuFV0Oz7DrnP`zrn`D~a%MbgXDp3(c literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/colorama/__pycache__/win32.cpython-311.pyc b/.venv/Lib/site-packages/colorama/__pycache__/win32.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..97532187003aab663a2c6ece52505296c67ed437 GIT binary patch literal 7927 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 Oz3%A&^OyZJ(EkVVA#dRT literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/colorama/__pycache__/winterm.cpython-311.pyc b/.venv/Lib/site-packages/colorama/__pycache__/winterm.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e4c21ae08934aff9b2ee331462e1ba77e82626c GIT binary patch literal 9153 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 XjzrVLUyVE*NwZ&GBvLD=S)={|g6SBj literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/colorama/tests/__pycache__/ansitowin32_test.cpython-311.pyc b/.venv/Lib/site-packages/colorama/tests/__pycache__/ansitowin32_test.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..87132ca73f79edd634e350db263972cc36e403f2 GIT binary patch literal 21521 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 As{jB1 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/colorama/tests/__pycache__/initialise_test.cpython-311.pyc b/.venv/Lib/site-packages/colorama/tests/__pycache__/initialise_test.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..52f40209e4b909c4a8537887a57f7fb7f66476ac GIT binary patch literal 14148 zcmdTrZEO?QmNT9iXJU^-0s$O00Ve^912F~4YfD>7T1bI5NwzB7)$1?#3e`N1W z_;7=sS3+7qJT-lyg7;MRA#Le`+DiSk;^$K7N&U0Cb~F-}B_yO3KiD5DvtcD(wLkWp zJD%~(*iKXWcH4I|oEhJH?ztc5+;h)4_wtW{fRBOnhky8M`RF=^`FH$bCZYPV$g>P{ zm5~{lO)*h?ds1xL6ZNFID3|7=P~3{STuMlLquz8&w1s6dtNIy5+{h3=Ym~Lt%HC%( z{AuP4_dau)m3di6`O^L<;_DY2<6iD}Tb`Usf9KwI9dnu({CvX3Y;sdz$(O`c6)FU{nwek}eM z<)XqwS(%A?aGVN1ZSt78Vd9zf=-W9HGW!_}=5snzSS)+aGfs?Xi_D#8qN2?(hic)gdTH~%2?WA~XUDShhc&p{EBTRT* zSv&-ShVq(QtDaROswQV=wNO$GWwKf*9@4b435zkn9b_*qoW%%$tIQm81K#z?$pBpB zN0{5}C`fvHTvZjKjb=4N*yY=7nOBw6l#0!SzCHQoo{6J?p-vo(PbMeh6WJLhb0j-U z63WDIDz2U!Jf=(z4$aIAj?ZdYl8mP&BBzwhsfl-zlM`xEQwC?^iIef;iaL?Vrm`fS zj&G++Vmq!VKu@X)T_cg1vt>b5w4*b*HggUl^miw8MC}HUXDVK%HE>VtSrB`Q;s#yZ zP%xiG9CYKUnSzq5jAolQ_jG91Dq$FnM@mMDSvpA*%{&)|wI*>&32M9BULwJ(?1$Mn z4vGL7SmuD4WpDL|RiY3=GvQ58H5zkH)?#&0Q{rTQ_H-uKVNHjb)ddKPApm*izPPz4 zZqdap1#!#$)uCT;mwnaO1>Xf9K}^T2cp-xd%rwkLbAhqX$h0*(8rH5R&@VuzrnT9o z!sno6&8|lGGJ}}x+5spnTU%zEF!w8L-&VgE#@5I78irF}$(-}|Gqh6cee+g$cPl6v zVPP~EtS)BtM0PeMhbEQKX}Z72v;<@zR9~`kGA@Uz^$cv1GxM-UH80#+_8SZNkP1tg z^uQdD^$2j?kPw0m0LnfCYn;r&CX`f@8Q7>Y35B#GhFb&!269y~(mJHrKX>%}}iF0YEwZVc=5W0Xh5K3EC$dJFtpM1=vC zFW7&#J)`5dVS_8PF`G*LR(v%TPfyD6y*8C7CxNY z8>nWOl$rsz8_Z%2ajWSwc-u{8uo~=?O*EGghgJjrHBxW=%nnB7PkRhEfo0x@7OPf< zXSD3eXtz1i26PE3eexWD+a9t8zqbQWvGq{M*!R|;b$}v>YDXQ*95XEK+y+Z58zT%L zp$`G%ng14i zA7h;-R>c~LMqf{#K5dj;%UkS#KF#+JG2C5-AL3i?wy*%dOJ2w>sP(-B1}m5XyeV%8 z@Smc~hj?ioyP@qGqVHjAag_XH(#K$)?b3s}q_fuyFoDf-1MM5%<$x`(ar7 z!c108o*}Ox58d{~`bI1q&00(Txh1(*Lwp$-_bUKk4hL4vzjZNoIaZtLpCH@*6Z+~> z*~}kDW!o+EX&#!P$w`~qy$uz3m zDZzS4IW&b8bG=K*h=H;f2&%Z

(Xh#uo!UdZ4Gm2(1GYSn>hRWuW7p)UzPMly% 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/colorama/tests/__pycache__/isatty_test.cpython-311.pyc b/.venv/Lib/site-packages/colorama/tests/__pycache__/isatty_test.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9953ed3a47a56b3f5a56a71adf481282f599c914 GIT binary patch literal 6713 zcmeHM-A^0Y6~E(|vB&lh%qE+{VkjvoSwq2)0GqH;Rt_Ic+HO(_sstCw9hhm>i$Cbh zkQ9`a(kc(x)vDQ6m9mk7O4UueD4@1~K}Fc-%7dl?S&Fn$pCa|a2&AU_)N}6mW5yVh zr0m;XkAFV*-ZN+J$M2qV@A%I(H9i9Azkm9f`~wdm|H4cm@p)nU6A^ zV3Mw=E6GM#hRCeUCAcIX<&*BH8}hvDPI!_+R7iTG-lQ+;OZub!q!<;U&U2eYYh2{} zL>6un*{ir7v4lK^ua%;Qlv>$0?ZTWYx`@I)0_m|;2?!RLQTh$}pJC~xkSi;UDVjbg zX-bw$O7YY)yc>#ZMs-z@l2=q|W=2u7{zyuTkEO4~Q>RWoV^D?9dS>RP-jmd1)~6~n z3291+P0nQx7v!`WzZOqP2`uzl#>U3Rv!W$lN~a(Fl>*Y zVUKCo@P5Yx=~;D3nHWh(+H~g?WwJ9eGt)UXt3#ip#6;J1C3St`NAbxCEv_q_Gt$(w zbWPDFrqYSDDkY_`4kN0Ctp~<1(={`f72;Y2KTccdq+84S(45hcjGw8#KriLLn9Uy?q)=?h%DV8JR>~G6U3LWfvePvw*zJ0lH-# z&?CD61xg>UER2$nH|x7d#{(zdF$*|YbQYdd`}SFIj_wD{%{^v8FHj#W++-d>iys$S zO`JJ~=&)=G$!Wh2=z0)OfCaaUJ+KhSC}|}0YP&dwKH!x^J46cj8 zg{zC#jHWKLsml<I(PD{=lI+0g(I&R7owH_KziIZiuISpf$tf(seP0#8} z3?-5k!YsEFp!B&B*WdfG6_w{3%Qg+J0|1cEq*x(LE%+8s-LHL6i>~Br32pmEHTvWO z4wSvn>xDq1mtAR%1o_o~2;ypxi?n!GTUeA^8I+GxxtEKa_N>0m0DeQ_y+}VwteqII zVpO$}7+Ge;)fSK(ByKJzv31la@;Fq5$4=GbX!<_@wrFdkvK8!r%5NF<9cDe{u~qgp zMA>}( zoK|Rj-`9rjhhF8AGZr|lIdjyuZO2it;EVz~9whSVWo#crbU64}BG^_S4w_n8hID<> zO$(lx)Dr;q-AS;*qEw1Y@j z0sh(A|5x2;J!`g}EfsDCj%);4)&ngM>pwsK$L7zPjX<{<=*|SXZ8a<3Tk2ZwGLD@w zkDW0B17=_#6BvN{d$qr-eJHFnEHy4S8ZCWhOP>+wHv|2dK!46tcr1O^7B*m~*p$-q z%Otw89e0)~9EdfxFiv!^ws6FD5NNhK&<0jh)vm(4+zkwd*gpgY>-fJ!-Z?+udD10< z{A7STf6o8p91HRq!+^ZzqB1Xn`dS?~__}xPbr$7%2IU4Shq%E`&ssMF=buJxBY#$g5*_Apa8wEb|!yX0T?8^K-^ueUdX=huVhjo^?O95TdVQyk8S z!==5;PgjCV&CAV3(`gg0cQ%?v)|*C*rVD1%1w*`OiWf8D#gc7y*=Gb#nRpFs1S9Lg zh!Gq#gM)@RWQs!>ap)yfb6#w>)p`rjV+}LtvYh31o!xTYb?tYHb+{a=8|q}g=;Vfa zJYV!OfR{qPtPqQ(q@)syWqq+&GA++0P!?mcU(8Agt40mt)P4uyO@wxYPJ}Q*55N*p z@zo7IsjEj(LcmC={Tkp_@sr~?9yXFi5IG*UltmC(9!}Fm@Uf^|1jvGN5qvxk?!5?y zcpk^0GFr{UMq!Wfe}Gsl6i|`ASz$I6*O90yZlzQX%ls1j9iXRg;NJoC{kn?lAj{9{ z@q|{sOQ1Ufx*X`6Fxvl3=UXj{G@)1*6i5puQG%a@64~W4H>p!lM`+Y{c7a) Q$SwNGv4ndAifMoU2Ti{!y?5r^Gw0*Z zJ-@lo}1F<3-emeE*aL0U1oVBciq(Z?cvXi`Qh&&9tI+(J{EgFP5Ex$wx|yUbw(D$637J5v+8?m&9NNJOacel~buz z=MY$u*;2fys#;pnP*pFkszqBbo5&|s^{cXG`Wlu5TNXvqh9rRmV-*DDd=Q8m^r}Qd zT~*Rbe1CL(VeFHBL>b%qcko~L7cAly@cYZgQ0}K1=c)mOkp%#Ct(L`7GprrN$3st{ z3<*wlLg?KX`f=iij$TcBM*;zYcbElo1Gdrzae%A0TfshCrb|s4HPGnfQ?da`xXAW`~FZl-Sc2#Wx75D=$`KN#bR)$-Rb`e$gCHTz(dE!(LaEI z2N+eAokOge&`j0QMDPoiW+JRZU^alJ&9IL6u)qJt%eGXgNq!OZPnk$*G5@8;ifkBs zFTl|x*7k+2eNTMc2a%5^)TJV3W6f$x#SG4AQpr^h5GJ^shp9!KMA@!izmZuC|E;%@-} zKXi-_$v=n2J3>2364;#%WxOl4(BPxhk^B)-700{1L>+5ZuEm%RzbxKDWqC;&?7BXWMX`Kpkf-R7%8 z;;!fw5_3hbh9wGr1g&H}dVta=N2;hqp?0>C^>@&+8!c=4D3LmH$i8fZ`r)KnpQzDj@us=7c(#X0d8=hQSl literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/colorama/tests/__pycache__/winterm_test.cpython-311.pyc b/.venv/Lib/site-packages/colorama/tests/__pycache__/winterm_test.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4ddff49e3e8baa54b324a9b33cf94a676a573e9c GIT binary patch literal 7241 zcmeHM+iw%u89#HgkL`)EfLx&=*#*I@HUYvGXjyd?Ldd3q&=Mnx70Gox6L9b)duB|Q zC`hTqLqMp@N=Pi#R*kw+7Q|NKp?&Q`{{kD0wAM&SNEHuxGlEuhRjK{H<9K|Hq1v?D zhdr73=3Kw?`JCT(IVWGXwfPC8e|+&v{aTQazha@Bl=aMuN07NobfODM62Y&S6jEYD zOi2+bB}Zg|_^?(=Dk)FIlk!Hq0!eRsn;3LAVF97k=Bu<_AZdA?d@Nlc^MWqxO46SS zL;@)_qNds+Z2}R=7|}h~iS9MTRf&*?@Rm{}Xl&8xWf4nE6^S9OLhfOy5h%5)t_ z!+37ex|%c`FVuw%mWm_Wa&nib14iB@28jqdiHIneF02Y58oZ^Xi`Pl5un`&hDTZg( zTkf+$%em^WF4b|8S7Ek?d=appt~7A=HI)FCv`zy5CQ0CJ;2hW_&a{CuZu@4eny-O# zThmqZH}nfO?H6e1w?$VciPq)>)}ezqT&jH%EVd*#92e`Ybe+nj?jDz^G;xX*s@q+I%^rG z(=%pRBbl_BNg9)JW*F(?*_j!Gji+Zaj>-%x%hJ&+v1Ha@0X{Znng+8*Kg!0EjuM^8 zFati*F)$0BsENw|Kz3x)NX|IE6c`KG%|k;D#Vk(h$heCp?pYtCZ!V4ecwu4M)oWj^ruH6C>nOPu9TY zyi5zb29~K!cNX41vFx+yyEgsNlPw)LuHL%3EElNyHSKy#yFT0gdC$tv^K`FG_vYx{ zH>uyT63f$lHr=AKQiPD(Wm)Ewm@*LRY;ums@aJ6T&Uj=(5&6ZSPo?Z}|)BpN>u_ z1*%l`cfG&q&39{dw|4(vo(|Y_AV&wDwg2Ewln<-ue5K5rMbI*N?O1mrX(Agfx+`e8MiyUjnt61B7>o8UG#cFK!V)OD!32qm;|Jn@o? zSYC3Gx+twwIqC9TpLb$SgZ8z5L0Ut1!Ei=~N*vZy?)2FktEa|Q%4p~EIJuuq!-&G2E7P}88lZ^^lZrP6`{{rL20 zswyaM>C@4L8uFB?p9F6P^Rx?kuvyn8`iufKY;qoaO*k192p}q5q4EK&q_zlNz9K z3y;w7-Spk=zoFhzm(@2w#`im2ISajRr`db30gW4s-rkY%Eb!V5J`SB4HyCSA0~2-> zNk5R9;P-nSBU)Le-@uW)Zs=aWij!)3UB2+ z#7(dpCsg-?>jpOxn04b9sCDB8n8Ee+)gxJ$9uTWp3=rgqa``OuG{DMjivtVu z29TOKpl`#Y_LGjDPiOATtb6>DhtJaza&74wWKjRcG36l|2_J2@vFK!&+in0>jo;U363w5hASc6 zV5|im*)Sr?1tUWT&qjc7$c>&oyCLK{Y9V(fJ;~=}Agy2ReWPD4nJAUTHQ10Ivb!jH6|G2sJeP=Pk6W{qctT5&+tMBN>(JiEp}qH&d}z=P4dxCU&nqLgGEx+` zDR@9dibGEbmCARBCr~p-NI6<0Kq_-!&FwkOmZa9#S=7x*!6+#C8VH1sNA%-!OL$h$%i7LV{?q@O*j+C}?!yw+umQIHVCMPhS zn#;i5E@SY|92pxOFE|UlvE}zQ{CcJo)pLye6j}ZZNk0<2ocV^nUxMpT*m)=dc8K{; zAVo`*IsUIC=l8SFeg5A`Ioo z!Hu4xhY12KY;$^h-*evbvbr74RI<9f@L1~3N!(JY@ No7`*Dr2B#<{TrB>M#=yH literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/colorama/tests/ansi_test.py b/.venv/Lib/site-packages/colorama/tests/ansi_test.py new file mode 100644 index 000000000..0a20c80f8 --- /dev/null +++ b/.venv/Lib/site-packages/colorama/tests/ansi_test.py @@ -0,0 +1,76 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import sys +from unittest import TestCase, main + +from ..ansi import Back, Fore, Style +from ..ansitowin32 import AnsiToWin32 + +stdout_orig = sys.stdout +stderr_orig = sys.stderr + + +class AnsiTest(TestCase): + + def setUp(self): + # sanity check: stdout should be a file or StringIO object. + # It will only be AnsiToWin32 if init() has previously wrapped it + self.assertNotEqual(type(sys.stdout), AnsiToWin32) + self.assertNotEqual(type(sys.stderr), AnsiToWin32) + + def tearDown(self): + sys.stdout = stdout_orig + sys.stderr = stderr_orig + + + def testForeAttributes(self): + self.assertEqual(Fore.BLACK, '\033[30m') + self.assertEqual(Fore.RED, '\033[31m') + self.assertEqual(Fore.GREEN, '\033[32m') + self.assertEqual(Fore.YELLOW, '\033[33m') + self.assertEqual(Fore.BLUE, '\033[34m') + self.assertEqual(Fore.MAGENTA, '\033[35m') + self.assertEqual(Fore.CYAN, '\033[36m') + self.assertEqual(Fore.WHITE, '\033[37m') + self.assertEqual(Fore.RESET, '\033[39m') + + # Check the light, extended versions. + self.assertEqual(Fore.LIGHTBLACK_EX, '\033[90m') + self.assertEqual(Fore.LIGHTRED_EX, '\033[91m') + self.assertEqual(Fore.LIGHTGREEN_EX, '\033[92m') + self.assertEqual(Fore.LIGHTYELLOW_EX, '\033[93m') + self.assertEqual(Fore.LIGHTBLUE_EX, '\033[94m') + self.assertEqual(Fore.LIGHTMAGENTA_EX, '\033[95m') + self.assertEqual(Fore.LIGHTCYAN_EX, '\033[96m') + self.assertEqual(Fore.LIGHTWHITE_EX, '\033[97m') + + + def testBackAttributes(self): + self.assertEqual(Back.BLACK, '\033[40m') + self.assertEqual(Back.RED, '\033[41m') + self.assertEqual(Back.GREEN, '\033[42m') + self.assertEqual(Back.YELLOW, '\033[43m') + self.assertEqual(Back.BLUE, '\033[44m') + self.assertEqual(Back.MAGENTA, '\033[45m') + self.assertEqual(Back.CYAN, '\033[46m') + self.assertEqual(Back.WHITE, '\033[47m') + self.assertEqual(Back.RESET, '\033[49m') + + # Check the light, extended versions. + self.assertEqual(Back.LIGHTBLACK_EX, '\033[100m') + self.assertEqual(Back.LIGHTRED_EX, '\033[101m') + self.assertEqual(Back.LIGHTGREEN_EX, '\033[102m') + self.assertEqual(Back.LIGHTYELLOW_EX, '\033[103m') + self.assertEqual(Back.LIGHTBLUE_EX, '\033[104m') + self.assertEqual(Back.LIGHTMAGENTA_EX, '\033[105m') + self.assertEqual(Back.LIGHTCYAN_EX, '\033[106m') + self.assertEqual(Back.LIGHTWHITE_EX, '\033[107m') + + + def testStyleAttributes(self): + self.assertEqual(Style.DIM, '\033[2m') + self.assertEqual(Style.NORMAL, '\033[22m') + self.assertEqual(Style.BRIGHT, '\033[1m') + + +if __name__ == '__main__': + main() diff --git a/.venv/Lib/site-packages/colorama/tests/ansitowin32_test.py b/.venv/Lib/site-packages/colorama/tests/ansitowin32_test.py new file mode 100644 index 000000000..91ca551f9 --- /dev/null +++ b/.venv/Lib/site-packages/colorama/tests/ansitowin32_test.py @@ -0,0 +1,294 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +from io import StringIO, TextIOWrapper +from unittest import TestCase, main +try: + from contextlib import ExitStack +except ImportError: + # python 2 + from contextlib2 import ExitStack + +try: + from unittest.mock import MagicMock, Mock, patch +except ImportError: + from mock import MagicMock, Mock, patch + +from ..ansitowin32 import AnsiToWin32, StreamWrapper +from ..win32 import ENABLE_VIRTUAL_TERMINAL_PROCESSING +from .utils import osname + + +class StreamWrapperTest(TestCase): + + def testIsAProxy(self): + mockStream = Mock() + wrapper = StreamWrapper(mockStream, None) + self.assertTrue( wrapper.random_attr is mockStream.random_attr ) + + def testDelegatesWrite(self): + mockStream = Mock() + mockConverter = Mock() + wrapper = StreamWrapper(mockStream, mockConverter) + wrapper.write('hello') + self.assertTrue(mockConverter.write.call_args, (('hello',), {})) + + def testDelegatesContext(self): + mockConverter = Mock() + s = StringIO() + with StreamWrapper(s, mockConverter) as fp: + fp.write(u'hello') + self.assertTrue(s.closed) + + def testProxyNoContextManager(self): + mockStream = MagicMock() + mockStream.__enter__.side_effect = AttributeError() + mockConverter = Mock() + with self.assertRaises(AttributeError) as excinfo: + with StreamWrapper(mockStream, mockConverter) as wrapper: + wrapper.write('hello') + + def test_closed_shouldnt_raise_on_closed_stream(self): + stream = StringIO() + stream.close() + wrapper = StreamWrapper(stream, None) + self.assertEqual(wrapper.closed, True) + + def test_closed_shouldnt_raise_on_detached_stream(self): + stream = TextIOWrapper(StringIO()) + stream.detach() + wrapper = StreamWrapper(stream, None) + self.assertEqual(wrapper.closed, True) + +class AnsiToWin32Test(TestCase): + + def testInit(self): + mockStdout = Mock() + auto = Mock() + stream = AnsiToWin32(mockStdout, autoreset=auto) + self.assertEqual(stream.wrapped, mockStdout) + self.assertEqual(stream.autoreset, auto) + + @patch('colorama.ansitowin32.winterm', None) + @patch('colorama.ansitowin32.winapi_test', lambda *_: True) + def testStripIsTrueOnWindows(self): + with osname('nt'): + mockStdout = Mock() + stream = AnsiToWin32(mockStdout) + self.assertTrue(stream.strip) + + def testStripIsFalseOffWindows(self): + with osname('posix'): + mockStdout = Mock(closed=False) + stream = AnsiToWin32(mockStdout) + self.assertFalse(stream.strip) + + def testWriteStripsAnsi(self): + mockStdout = Mock() + stream = AnsiToWin32(mockStdout) + stream.wrapped = Mock() + stream.write_and_convert = Mock() + stream.strip = True + + stream.write('abc') + + self.assertFalse(stream.wrapped.write.called) + self.assertEqual(stream.write_and_convert.call_args, (('abc',), {})) + + def testWriteDoesNotStripAnsi(self): + mockStdout = Mock() + stream = AnsiToWin32(mockStdout) + stream.wrapped = Mock() + stream.write_and_convert = Mock() + stream.strip = False + stream.convert = False + + stream.write('abc') + + self.assertFalse(stream.write_and_convert.called) + self.assertEqual(stream.wrapped.write.call_args, (('abc',), {})) + + def assert_autoresets(self, convert, autoreset=True): + stream = AnsiToWin32(Mock()) + stream.convert = convert + stream.reset_all = Mock() + stream.autoreset = autoreset + stream.winterm = Mock() + + stream.write('abc') + + self.assertEqual(stream.reset_all.called, autoreset) + + def testWriteAutoresets(self): + self.assert_autoresets(convert=True) + self.assert_autoresets(convert=False) + self.assert_autoresets(convert=True, autoreset=False) + self.assert_autoresets(convert=False, autoreset=False) + + def testWriteAndConvertWritesPlainText(self): + stream = AnsiToWin32(Mock()) + stream.write_and_convert( 'abc' ) + self.assertEqual( stream.wrapped.write.call_args, (('abc',), {}) ) + + def testWriteAndConvertStripsAllValidAnsi(self): + stream = AnsiToWin32(Mock()) + stream.call_win32 = Mock() + data = [ + 'abc\033[mdef', + 'abc\033[0mdef', + 'abc\033[2mdef', + 'abc\033[02mdef', + 'abc\033[002mdef', + 'abc\033[40mdef', + 'abc\033[040mdef', + 'abc\033[0;1mdef', + 'abc\033[40;50mdef', + 'abc\033[50;30;40mdef', + 'abc\033[Adef', + 'abc\033[0Gdef', + 'abc\033[1;20;128Hdef', + ] + for datum in data: + stream.wrapped.write.reset_mock() + stream.write_and_convert( datum ) + self.assertEqual( + [args[0] for args in stream.wrapped.write.call_args_list], + [ ('abc',), ('def',) ] + ) + + def testWriteAndConvertSkipsEmptySnippets(self): + stream = AnsiToWin32(Mock()) + stream.call_win32 = Mock() + stream.write_and_convert( '\033[40m\033[41m' ) + self.assertFalse( stream.wrapped.write.called ) + + def testWriteAndConvertCallsWin32WithParamsAndCommand(self): + stream = AnsiToWin32(Mock()) + stream.convert = True + stream.call_win32 = Mock() + stream.extract_params = Mock(return_value='params') + data = { + 'abc\033[adef': ('a', 'params'), + 'abc\033[;;bdef': ('b', 'params'), + 'abc\033[0cdef': ('c', 'params'), + 'abc\033[;;0;;Gdef': ('G', 'params'), + 'abc\033[1;20;128Hdef': ('H', 'params'), + } + for datum, expected in data.items(): + stream.call_win32.reset_mock() + stream.write_and_convert( datum ) + self.assertEqual( stream.call_win32.call_args[0], expected ) + + def test_reset_all_shouldnt_raise_on_closed_orig_stdout(self): + stream = StringIO() + converter = AnsiToWin32(stream) + stream.close() + + converter.reset_all() + + def test_wrap_shouldnt_raise_on_closed_orig_stdout(self): + stream = StringIO() + stream.close() + with \ + patch("colorama.ansitowin32.os.name", "nt"), \ + patch("colorama.ansitowin32.winapi_test", lambda: True): + converter = AnsiToWin32(stream) + self.assertTrue(converter.strip) + self.assertFalse(converter.convert) + + def test_wrap_shouldnt_raise_on_missing_closed_attr(self): + with \ + patch("colorama.ansitowin32.os.name", "nt"), \ + patch("colorama.ansitowin32.winapi_test", lambda: True): + converter = AnsiToWin32(object()) + self.assertTrue(converter.strip) + self.assertFalse(converter.convert) + + def testExtractParams(self): + stream = AnsiToWin32(Mock()) + data = { + '': (0,), + ';;': (0,), + '2': (2,), + ';;002;;': (2,), + '0;1': (0, 1), + ';;003;;456;;': (3, 456), + '11;22;33;44;55': (11, 22, 33, 44, 55), + } + for datum, expected in data.items(): + self.assertEqual(stream.extract_params('m', datum), expected) + + def testCallWin32UsesLookup(self): + listener = Mock() + stream = AnsiToWin32(listener) + stream.win32_calls = { + 1: (lambda *_, **__: listener(11),), + 2: (lambda *_, **__: listener(22),), + 3: (lambda *_, **__: listener(33),), + } + stream.call_win32('m', (3, 1, 99, 2)) + self.assertEqual( + [a[0][0] for a in listener.call_args_list], + [33, 11, 22] ) + + def test_osc_codes(self): + mockStdout = Mock() + stream = AnsiToWin32(mockStdout, convert=True) + with patch('colorama.ansitowin32.winterm') as winterm: + data = [ + '\033]0\x07', # missing arguments + '\033]0;foo\x08', # wrong OSC command + '\033]0;colorama_test_title\x07', # should work + '\033]1;colorama_test_title\x07', # wrong set command + '\033]2;colorama_test_title\x07', # should work + '\033]' + ';' * 64 + '\x08', # see issue #247 + ] + for code in data: + stream.write(code) + self.assertEqual(winterm.set_title.call_count, 2) + + def test_native_windows_ansi(self): + with ExitStack() as stack: + def p(a, b): + stack.enter_context(patch(a, b, create=True)) + # Pretend to be on Windows + p("colorama.ansitowin32.os.name", "nt") + p("colorama.ansitowin32.winapi_test", lambda: True) + p("colorama.win32.winapi_test", lambda: True) + p("colorama.winterm.win32.windll", "non-None") + p("colorama.winterm.get_osfhandle", lambda _: 1234) + + # Pretend that our mock stream has native ANSI support + p( + "colorama.winterm.win32.GetConsoleMode", + lambda _: ENABLE_VIRTUAL_TERMINAL_PROCESSING, + ) + SetConsoleMode = Mock() + p("colorama.winterm.win32.SetConsoleMode", SetConsoleMode) + + stdout = Mock() + stdout.closed = False + stdout.isatty.return_value = True + stdout.fileno.return_value = 1 + + # Our fake console says it has native vt support, so AnsiToWin32 should + # enable that support and do nothing else. + stream = AnsiToWin32(stdout) + SetConsoleMode.assert_called_with(1234, ENABLE_VIRTUAL_TERMINAL_PROCESSING) + self.assertFalse(stream.strip) + self.assertFalse(stream.convert) + self.assertFalse(stream.should_wrap()) + + # Now let's pretend we're on an old Windows console, that doesn't have + # native ANSI support. + p("colorama.winterm.win32.GetConsoleMode", lambda _: 0) + SetConsoleMode = Mock() + p("colorama.winterm.win32.SetConsoleMode", SetConsoleMode) + + stream = AnsiToWin32(stdout) + SetConsoleMode.assert_called_with(1234, ENABLE_VIRTUAL_TERMINAL_PROCESSING) + self.assertTrue(stream.strip) + self.assertTrue(stream.convert) + self.assertTrue(stream.should_wrap()) + + +if __name__ == '__main__': + main() diff --git a/.venv/Lib/site-packages/colorama/tests/initialise_test.py b/.venv/Lib/site-packages/colorama/tests/initialise_test.py new file mode 100644 index 000000000..89f9b0751 --- /dev/null +++ b/.venv/Lib/site-packages/colorama/tests/initialise_test.py @@ -0,0 +1,189 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import sys +from unittest import TestCase, main, skipUnless + +try: + from unittest.mock import patch, Mock +except ImportError: + from mock import patch, Mock + +from ..ansitowin32 import StreamWrapper +from ..initialise import init, just_fix_windows_console, _wipe_internal_state_for_tests +from .utils import osname, replace_by + +orig_stdout = sys.stdout +orig_stderr = sys.stderr + + +class InitTest(TestCase): + + @skipUnless(sys.stdout.isatty(), "sys.stdout is not a tty") + def setUp(self): + # sanity check + self.assertNotWrapped() + + def tearDown(self): + _wipe_internal_state_for_tests() + sys.stdout = orig_stdout + sys.stderr = orig_stderr + + def assertWrapped(self): + self.assertIsNot(sys.stdout, orig_stdout, 'stdout should be wrapped') + self.assertIsNot(sys.stderr, orig_stderr, 'stderr should be wrapped') + self.assertTrue(isinstance(sys.stdout, StreamWrapper), + 'bad stdout wrapper') + self.assertTrue(isinstance(sys.stderr, StreamWrapper), + 'bad stderr wrapper') + + def assertNotWrapped(self): + self.assertIs(sys.stdout, orig_stdout, 'stdout should not be wrapped') + self.assertIs(sys.stderr, orig_stderr, 'stderr should not be wrapped') + + @patch('colorama.initialise.reset_all') + @patch('colorama.ansitowin32.winapi_test', lambda *_: True) + @patch('colorama.ansitowin32.enable_vt_processing', lambda *_: False) + def testInitWrapsOnWindows(self, _): + with osname("nt"): + init() + self.assertWrapped() + + @patch('colorama.initialise.reset_all') + @patch('colorama.ansitowin32.winapi_test', lambda *_: False) + def testInitDoesntWrapOnEmulatedWindows(self, _): + with osname("nt"): + init() + self.assertNotWrapped() + + def testInitDoesntWrapOnNonWindows(self): + with osname("posix"): + init() + self.assertNotWrapped() + + def testInitDoesntWrapIfNone(self): + with replace_by(None): + init() + # We can't use assertNotWrapped here because replace_by(None) + # changes stdout/stderr already. + self.assertIsNone(sys.stdout) + self.assertIsNone(sys.stderr) + + def testInitAutoresetOnWrapsOnAllPlatforms(self): + with osname("posix"): + init(autoreset=True) + self.assertWrapped() + + def testInitWrapOffDoesntWrapOnWindows(self): + with osname("nt"): + init(wrap=False) + self.assertNotWrapped() + + def testInitWrapOffIncompatibleWithAutoresetOn(self): + self.assertRaises(ValueError, lambda: init(autoreset=True, wrap=False)) + + @patch('colorama.win32.SetConsoleTextAttribute') + @patch('colorama.initialise.AnsiToWin32') + def testAutoResetPassedOn(self, mockATW32, _): + with osname("nt"): + init(autoreset=True) + self.assertEqual(len(mockATW32.call_args_list), 2) + self.assertEqual(mockATW32.call_args_list[1][1]['autoreset'], True) + self.assertEqual(mockATW32.call_args_list[0][1]['autoreset'], True) + + @patch('colorama.initialise.AnsiToWin32') + def testAutoResetChangeable(self, mockATW32): + with osname("nt"): + init() + + init(autoreset=True) + self.assertEqual(len(mockATW32.call_args_list), 4) + self.assertEqual(mockATW32.call_args_list[2][1]['autoreset'], True) + self.assertEqual(mockATW32.call_args_list[3][1]['autoreset'], True) + + init() + self.assertEqual(len(mockATW32.call_args_list), 6) + self.assertEqual( + mockATW32.call_args_list[4][1]['autoreset'], False) + self.assertEqual( + mockATW32.call_args_list[5][1]['autoreset'], False) + + + @patch('colorama.initialise.atexit.register') + def testAtexitRegisteredOnlyOnce(self, mockRegister): + init() + self.assertTrue(mockRegister.called) + mockRegister.reset_mock() + init() + self.assertFalse(mockRegister.called) + + +class JustFixWindowsConsoleTest(TestCase): + def _reset(self): + _wipe_internal_state_for_tests() + sys.stdout = orig_stdout + sys.stderr = orig_stderr + + def tearDown(self): + self._reset() + + @patch("colorama.ansitowin32.winapi_test", lambda: True) + def testJustFixWindowsConsole(self): + if sys.platform != "win32": + # just_fix_windows_console should be a no-op + just_fix_windows_console() + self.assertIs(sys.stdout, orig_stdout) + self.assertIs(sys.stderr, orig_stderr) + else: + def fake_std(): + # Emulate stdout=not a tty, stderr=tty + # to check that we handle both cases correctly + stdout = Mock() + stdout.closed = False + stdout.isatty.return_value = False + stdout.fileno.return_value = 1 + sys.stdout = stdout + + stderr = Mock() + stderr.closed = False + stderr.isatty.return_value = True + stderr.fileno.return_value = 2 + sys.stderr = stderr + + for native_ansi in [False, True]: + with patch( + 'colorama.ansitowin32.enable_vt_processing', + lambda *_: native_ansi + ): + self._reset() + fake_std() + + # Regular single-call test + prev_stdout = sys.stdout + prev_stderr = sys.stderr + just_fix_windows_console() + self.assertIs(sys.stdout, prev_stdout) + if native_ansi: + self.assertIs(sys.stderr, prev_stderr) + else: + self.assertIsNot(sys.stderr, prev_stderr) + + # second call without resetting is always a no-op + prev_stdout = sys.stdout + prev_stderr = sys.stderr + just_fix_windows_console() + self.assertIs(sys.stdout, prev_stdout) + self.assertIs(sys.stderr, prev_stderr) + + self._reset() + fake_std() + + # If init() runs first, just_fix_windows_console should be a no-op + init() + prev_stdout = sys.stdout + prev_stderr = sys.stderr + just_fix_windows_console() + self.assertIs(prev_stdout, sys.stdout) + self.assertIs(prev_stderr, sys.stderr) + + +if __name__ == '__main__': + main() diff --git a/.venv/Lib/site-packages/colorama/tests/isatty_test.py b/.venv/Lib/site-packages/colorama/tests/isatty_test.py new file mode 100644 index 000000000..0f84e4bef --- /dev/null +++ b/.venv/Lib/site-packages/colorama/tests/isatty_test.py @@ -0,0 +1,57 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import sys +from unittest import TestCase, main + +from ..ansitowin32 import StreamWrapper, AnsiToWin32 +from .utils import pycharm, replace_by, replace_original_by, StreamTTY, StreamNonTTY + + +def is_a_tty(stream): + return StreamWrapper(stream, None).isatty() + +class IsattyTest(TestCase): + + def test_TTY(self): + tty = StreamTTY() + self.assertTrue(is_a_tty(tty)) + with pycharm(): + self.assertTrue(is_a_tty(tty)) + + def test_nonTTY(self): + non_tty = StreamNonTTY() + self.assertFalse(is_a_tty(non_tty)) + with pycharm(): + self.assertFalse(is_a_tty(non_tty)) + + def test_withPycharm(self): + with pycharm(): + self.assertTrue(is_a_tty(sys.stderr)) + self.assertTrue(is_a_tty(sys.stdout)) + + def test_withPycharmTTYOverride(self): + tty = StreamTTY() + with pycharm(), replace_by(tty): + self.assertTrue(is_a_tty(tty)) + + def test_withPycharmNonTTYOverride(self): + non_tty = StreamNonTTY() + with pycharm(), replace_by(non_tty): + self.assertFalse(is_a_tty(non_tty)) + + def test_withPycharmNoneOverride(self): + with pycharm(): + with replace_by(None), replace_original_by(None): + self.assertFalse(is_a_tty(None)) + self.assertFalse(is_a_tty(StreamNonTTY())) + self.assertTrue(is_a_tty(StreamTTY())) + + def test_withPycharmStreamWrapped(self): + with pycharm(): + self.assertTrue(AnsiToWin32(StreamTTY()).stream.isatty()) + self.assertFalse(AnsiToWin32(StreamNonTTY()).stream.isatty()) + self.assertTrue(AnsiToWin32(sys.stdout).stream.isatty()) + self.assertTrue(AnsiToWin32(sys.stderr).stream.isatty()) + + +if __name__ == '__main__': + main() diff --git a/.venv/Lib/site-packages/colorama/tests/utils.py b/.venv/Lib/site-packages/colorama/tests/utils.py new file mode 100644 index 000000000..472fafb44 --- /dev/null +++ b/.venv/Lib/site-packages/colorama/tests/utils.py @@ -0,0 +1,49 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +from contextlib import contextmanager +from io import StringIO +import sys +import os + + +class StreamTTY(StringIO): + def isatty(self): + return True + +class StreamNonTTY(StringIO): + def isatty(self): + return False + +@contextmanager +def osname(name): + orig = os.name + os.name = name + yield + os.name = orig + +@contextmanager +def replace_by(stream): + orig_stdout = sys.stdout + orig_stderr = sys.stderr + sys.stdout = stream + sys.stderr = stream + yield + sys.stdout = orig_stdout + sys.stderr = orig_stderr + +@contextmanager +def replace_original_by(stream): + orig_stdout = sys.__stdout__ + orig_stderr = sys.__stderr__ + sys.__stdout__ = stream + sys.__stderr__ = stream + yield + sys.__stdout__ = orig_stdout + sys.__stderr__ = orig_stderr + +@contextmanager +def pycharm(): + os.environ["PYCHARM_HOSTED"] = "1" + non_tty = StreamNonTTY() + with replace_by(non_tty), replace_original_by(non_tty): + yield + del os.environ["PYCHARM_HOSTED"] diff --git a/.venv/Lib/site-packages/colorama/tests/winterm_test.py b/.venv/Lib/site-packages/colorama/tests/winterm_test.py new file mode 100644 index 000000000..d0955f9e6 --- /dev/null +++ b/.venv/Lib/site-packages/colorama/tests/winterm_test.py @@ -0,0 +1,131 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import sys +from unittest import TestCase, main, skipUnless + +try: + from unittest.mock import Mock, patch +except ImportError: + from mock import Mock, patch + +from ..winterm import WinColor, WinStyle, WinTerm + + +class WinTermTest(TestCase): + + @patch('colorama.winterm.win32') + def testInit(self, mockWin32): + mockAttr = Mock() + mockAttr.wAttributes = 7 + 6 * 16 + 8 + mockWin32.GetConsoleScreenBufferInfo.return_value = mockAttr + term = WinTerm() + self.assertEqual(term._fore, 7) + self.assertEqual(term._back, 6) + self.assertEqual(term._style, 8) + + @skipUnless(sys.platform.startswith("win"), "requires Windows") + def testGetAttrs(self): + term = WinTerm() + + term._fore = 0 + term._back = 0 + term._style = 0 + self.assertEqual(term.get_attrs(), 0) + + term._fore = WinColor.YELLOW + self.assertEqual(term.get_attrs(), WinColor.YELLOW) + + term._back = WinColor.MAGENTA + self.assertEqual( + term.get_attrs(), + WinColor.YELLOW + WinColor.MAGENTA * 16) + + term._style = WinStyle.BRIGHT + self.assertEqual( + term.get_attrs(), + WinColor.YELLOW + WinColor.MAGENTA * 16 + WinStyle.BRIGHT) + + @patch('colorama.winterm.win32') + def testResetAll(self, mockWin32): + mockAttr = Mock() + mockAttr.wAttributes = 1 + 2 * 16 + 8 + mockWin32.GetConsoleScreenBufferInfo.return_value = mockAttr + term = WinTerm() + + term.set_console = Mock() + term._fore = -1 + term._back = -1 + term._style = -1 + + term.reset_all() + + self.assertEqual(term._fore, 1) + self.assertEqual(term._back, 2) + self.assertEqual(term._style, 8) + self.assertEqual(term.set_console.called, True) + + @skipUnless(sys.platform.startswith("win"), "requires Windows") + def testFore(self): + term = WinTerm() + term.set_console = Mock() + term._fore = 0 + + term.fore(5) + + self.assertEqual(term._fore, 5) + self.assertEqual(term.set_console.called, True) + + @skipUnless(sys.platform.startswith("win"), "requires Windows") + def testBack(self): + term = WinTerm() + term.set_console = Mock() + term._back = 0 + + term.back(5) + + self.assertEqual(term._back, 5) + self.assertEqual(term.set_console.called, True) + + @skipUnless(sys.platform.startswith("win"), "requires Windows") + def testStyle(self): + term = WinTerm() + term.set_console = Mock() + term._style = 0 + + term.style(22) + + self.assertEqual(term._style, 22) + self.assertEqual(term.set_console.called, True) + + @patch('colorama.winterm.win32') + def testSetConsole(self, mockWin32): + mockAttr = Mock() + mockAttr.wAttributes = 0 + mockWin32.GetConsoleScreenBufferInfo.return_value = mockAttr + term = WinTerm() + term.windll = Mock() + + term.set_console() + + self.assertEqual( + mockWin32.SetConsoleTextAttribute.call_args, + ((mockWin32.STDOUT, term.get_attrs()), {}) + ) + + @patch('colorama.winterm.win32') + def testSetConsoleOnStderr(self, mockWin32): + mockAttr = Mock() + mockAttr.wAttributes = 0 + mockWin32.GetConsoleScreenBufferInfo.return_value = mockAttr + term = WinTerm() + term.windll = Mock() + + term.set_console(on_stderr=True) + + self.assertEqual( + mockWin32.SetConsoleTextAttribute.call_args, + ((mockWin32.STDERR, term.get_attrs()), {}) + ) + + +if __name__ == '__main__': + main() diff --git a/.venv/Lib/site-packages/colorama/win32.py b/.venv/Lib/site-packages/colorama/win32.py new file mode 100644 index 000000000..841b0e270 --- /dev/null +++ b/.venv/Lib/site-packages/colorama/win32.py @@ -0,0 +1,180 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. + +# from winbase.h +STDOUT = -11 +STDERR = -12 + +ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 + +try: + import ctypes + from ctypes import LibraryLoader + windll = LibraryLoader(ctypes.WinDLL) + from ctypes import wintypes +except (AttributeError, ImportError): + windll = None + SetConsoleTextAttribute = lambda *_: None + winapi_test = lambda *_: None +else: + from ctypes import byref, Structure, c_char, POINTER + + COORD = wintypes._COORD + + class CONSOLE_SCREEN_BUFFER_INFO(Structure): + """struct in wincon.h.""" + _fields_ = [ + ("dwSize", COORD), + ("dwCursorPosition", COORD), + ("wAttributes", wintypes.WORD), + ("srWindow", wintypes.SMALL_RECT), + ("dwMaximumWindowSize", COORD), + ] + def __str__(self): + return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % ( + self.dwSize.Y, self.dwSize.X + , self.dwCursorPosition.Y, self.dwCursorPosition.X + , self.wAttributes + , self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right + , self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X + ) + + _GetStdHandle = windll.kernel32.GetStdHandle + _GetStdHandle.argtypes = [ + wintypes.DWORD, + ] + _GetStdHandle.restype = wintypes.HANDLE + + _GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo + _GetConsoleScreenBufferInfo.argtypes = [ + wintypes.HANDLE, + POINTER(CONSOLE_SCREEN_BUFFER_INFO), + ] + _GetConsoleScreenBufferInfo.restype = wintypes.BOOL + + _SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute + _SetConsoleTextAttribute.argtypes = [ + wintypes.HANDLE, + wintypes.WORD, + ] + _SetConsoleTextAttribute.restype = wintypes.BOOL + + _SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition + _SetConsoleCursorPosition.argtypes = [ + wintypes.HANDLE, + COORD, + ] + _SetConsoleCursorPosition.restype = wintypes.BOOL + + _FillConsoleOutputCharacterA = windll.kernel32.FillConsoleOutputCharacterA + _FillConsoleOutputCharacterA.argtypes = [ + wintypes.HANDLE, + c_char, + wintypes.DWORD, + COORD, + POINTER(wintypes.DWORD), + ] + _FillConsoleOutputCharacterA.restype = wintypes.BOOL + + _FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute + _FillConsoleOutputAttribute.argtypes = [ + wintypes.HANDLE, + wintypes.WORD, + wintypes.DWORD, + COORD, + POINTER(wintypes.DWORD), + ] + _FillConsoleOutputAttribute.restype = wintypes.BOOL + + _SetConsoleTitleW = windll.kernel32.SetConsoleTitleW + _SetConsoleTitleW.argtypes = [ + wintypes.LPCWSTR + ] + _SetConsoleTitleW.restype = wintypes.BOOL + + _GetConsoleMode = windll.kernel32.GetConsoleMode + _GetConsoleMode.argtypes = [ + wintypes.HANDLE, + POINTER(wintypes.DWORD) + ] + _GetConsoleMode.restype = wintypes.BOOL + + _SetConsoleMode = windll.kernel32.SetConsoleMode + _SetConsoleMode.argtypes = [ + wintypes.HANDLE, + wintypes.DWORD + ] + _SetConsoleMode.restype = wintypes.BOOL + + def _winapi_test(handle): + csbi = CONSOLE_SCREEN_BUFFER_INFO() + success = _GetConsoleScreenBufferInfo( + handle, byref(csbi)) + return bool(success) + + def winapi_test(): + return any(_winapi_test(h) for h in + (_GetStdHandle(STDOUT), _GetStdHandle(STDERR))) + + def GetConsoleScreenBufferInfo(stream_id=STDOUT): + handle = _GetStdHandle(stream_id) + csbi = CONSOLE_SCREEN_BUFFER_INFO() + success = _GetConsoleScreenBufferInfo( + handle, byref(csbi)) + return csbi + + def SetConsoleTextAttribute(stream_id, attrs): + handle = _GetStdHandle(stream_id) + return _SetConsoleTextAttribute(handle, attrs) + + def SetConsoleCursorPosition(stream_id, position, adjust=True): + position = COORD(*position) + # If the position is out of range, do nothing. + if position.Y <= 0 or position.X <= 0: + return + # Adjust for Windows' SetConsoleCursorPosition: + # 1. being 0-based, while ANSI is 1-based. + # 2. expecting (x,y), while ANSI uses (y,x). + adjusted_position = COORD(position.Y - 1, position.X - 1) + if adjust: + # Adjust for viewport's scroll position + sr = GetConsoleScreenBufferInfo(STDOUT).srWindow + adjusted_position.Y += sr.Top + adjusted_position.X += sr.Left + # Resume normal processing + handle = _GetStdHandle(stream_id) + return _SetConsoleCursorPosition(handle, adjusted_position) + + def FillConsoleOutputCharacter(stream_id, char, length, start): + handle = _GetStdHandle(stream_id) + char = c_char(char.encode()) + length = wintypes.DWORD(length) + num_written = wintypes.DWORD(0) + # Note that this is hard-coded for ANSI (vs wide) bytes. + success = _FillConsoleOutputCharacterA( + handle, char, length, start, byref(num_written)) + return num_written.value + + def FillConsoleOutputAttribute(stream_id, attr, length, start): + ''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )''' + handle = _GetStdHandle(stream_id) + attribute = wintypes.WORD(attr) + length = wintypes.DWORD(length) + num_written = wintypes.DWORD(0) + # Note that this is hard-coded for ANSI (vs wide) bytes. + return _FillConsoleOutputAttribute( + handle, attribute, length, start, byref(num_written)) + + def SetConsoleTitle(title): + return _SetConsoleTitleW(title) + + def GetConsoleMode(handle): + mode = wintypes.DWORD() + success = _GetConsoleMode(handle, byref(mode)) + if not success: + raise ctypes.WinError() + return mode.value + + def SetConsoleMode(handle, mode): + success = _SetConsoleMode(handle, mode) + if not success: + raise ctypes.WinError() diff --git a/.venv/Lib/site-packages/colorama/winterm.py b/.venv/Lib/site-packages/colorama/winterm.py new file mode 100644 index 000000000..aad867e8c --- /dev/null +++ b/.venv/Lib/site-packages/colorama/winterm.py @@ -0,0 +1,195 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +try: + from msvcrt import get_osfhandle +except ImportError: + def get_osfhandle(_): + raise OSError("This isn't windows!") + + +from . import win32 + +# from wincon.h +class WinColor(object): + BLACK = 0 + BLUE = 1 + GREEN = 2 + CYAN = 3 + RED = 4 + MAGENTA = 5 + YELLOW = 6 + GREY = 7 + +# from wincon.h +class WinStyle(object): + NORMAL = 0x00 # dim text, dim background + BRIGHT = 0x08 # bright text, dim background + BRIGHT_BACKGROUND = 0x80 # dim text, bright background + +class WinTerm(object): + + def __init__(self): + self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes + self.set_attrs(self._default) + self._default_fore = self._fore + self._default_back = self._back + self._default_style = self._style + # In order to emulate LIGHT_EX in windows, we borrow the BRIGHT style. + # So that LIGHT_EX colors and BRIGHT style do not clobber each other, + # we track them separately, since LIGHT_EX is overwritten by Fore/Back + # and BRIGHT is overwritten by Style codes. + self._light = 0 + + def get_attrs(self): + return self._fore + self._back * 16 + (self._style | self._light) + + def set_attrs(self, value): + self._fore = value & 7 + self._back = (value >> 4) & 7 + self._style = value & (WinStyle.BRIGHT | WinStyle.BRIGHT_BACKGROUND) + + def reset_all(self, on_stderr=None): + self.set_attrs(self._default) + self.set_console(attrs=self._default) + self._light = 0 + + def fore(self, fore=None, light=False, on_stderr=False): + if fore is None: + fore = self._default_fore + self._fore = fore + # Emulate LIGHT_EX with BRIGHT Style + if light: + self._light |= WinStyle.BRIGHT + else: + self._light &= ~WinStyle.BRIGHT + self.set_console(on_stderr=on_stderr) + + def back(self, back=None, light=False, on_stderr=False): + if back is None: + back = self._default_back + self._back = back + # Emulate LIGHT_EX with BRIGHT_BACKGROUND Style + if light: + self._light |= WinStyle.BRIGHT_BACKGROUND + else: + self._light &= ~WinStyle.BRIGHT_BACKGROUND + self.set_console(on_stderr=on_stderr) + + def style(self, style=None, on_stderr=False): + if style is None: + style = self._default_style + self._style = style + self.set_console(on_stderr=on_stderr) + + def set_console(self, attrs=None, on_stderr=False): + if attrs is None: + attrs = self.get_attrs() + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + win32.SetConsoleTextAttribute(handle, attrs) + + def get_position(self, handle): + position = win32.GetConsoleScreenBufferInfo(handle).dwCursorPosition + # Because Windows coordinates are 0-based, + # and win32.SetConsoleCursorPosition expects 1-based. + position.X += 1 + position.Y += 1 + return position + + def set_cursor_position(self, position=None, on_stderr=False): + if position is None: + # I'm not currently tracking the position, so there is no default. + # position = self.get_position() + return + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + win32.SetConsoleCursorPosition(handle, position) + + def cursor_adjust(self, x, y, on_stderr=False): + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + position = self.get_position(handle) + adjusted_position = (position.Y + y, position.X + x) + win32.SetConsoleCursorPosition(handle, adjusted_position, adjust=False) + + def erase_screen(self, mode=0, on_stderr=False): + # 0 should clear from the cursor to the end of the screen. + # 1 should clear from the cursor to the beginning of the screen. + # 2 should clear the entire screen, and move cursor to (1,1) + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + csbi = win32.GetConsoleScreenBufferInfo(handle) + # get the number of character cells in the current buffer + cells_in_screen = csbi.dwSize.X * csbi.dwSize.Y + # get number of character cells before current cursor position + cells_before_cursor = csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X + if mode == 0: + from_coord = csbi.dwCursorPosition + cells_to_erase = cells_in_screen - cells_before_cursor + elif mode == 1: + from_coord = win32.COORD(0, 0) + cells_to_erase = cells_before_cursor + elif mode == 2: + from_coord = win32.COORD(0, 0) + cells_to_erase = cells_in_screen + else: + # invalid mode + return + # fill the entire screen with blanks + win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) + # now set the buffer's attributes accordingly + win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) + if mode == 2: + # put the cursor where needed + win32.SetConsoleCursorPosition(handle, (1, 1)) + + def erase_line(self, mode=0, on_stderr=False): + # 0 should clear from the cursor to the end of the line. + # 1 should clear from the cursor to the beginning of the line. + # 2 should clear the entire line. + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + csbi = win32.GetConsoleScreenBufferInfo(handle) + if mode == 0: + from_coord = csbi.dwCursorPosition + cells_to_erase = csbi.dwSize.X - csbi.dwCursorPosition.X + elif mode == 1: + from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) + cells_to_erase = csbi.dwCursorPosition.X + elif mode == 2: + from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) + cells_to_erase = csbi.dwSize.X + else: + # invalid mode + return + # fill the entire screen with blanks + win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) + # now set the buffer's attributes accordingly + win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) + + def set_title(self, title): + win32.SetConsoleTitle(title) + + +def enable_vt_processing(fd): + if win32.windll is None or not win32.winapi_test(): + return False + + try: + handle = get_osfhandle(fd) + mode = win32.GetConsoleMode(handle) + win32.SetConsoleMode( + handle, + mode | win32.ENABLE_VIRTUAL_TERMINAL_PROCESSING, + ) + + mode = win32.GetConsoleMode(handle) + if mode & win32.ENABLE_VIRTUAL_TERMINAL_PROCESSING: + return True + # Can get TypeError in testsuite where 'fd' is a Mock() + except (OSError, TypeError): + return False diff --git a/.venv/Lib/site-packages/distutils-precedence.pth b/.venv/Lib/site-packages/distutils-precedence.pth new file mode 100644 index 000000000..7f009fe9b --- /dev/null +++ b/.venv/Lib/site-packages/distutils-precedence.pth @@ -0,0 +1 @@ +import os; var = 'SETUPTOOLS_USE_DISTUTILS'; enabled = os.environ.get(var, 'local') == 'local'; enabled and __import__('_distutils_hack').add_shim(); diff --git a/.venv/Lib/site-packages/flask/__init__.py b/.venv/Lib/site-packages/flask/__init__.py new file mode 100644 index 000000000..0bef2213b --- /dev/null +++ b/.venv/Lib/site-packages/flask/__init__.py @@ -0,0 +1,102 @@ +from . import json as json +from .app import Flask as Flask +from .app import Request as Request +from .app import Response as Response +from .blueprints import Blueprint as Blueprint +from .config import Config as Config +from .ctx import after_this_request as after_this_request +from .ctx import copy_current_request_context as copy_current_request_context +from .ctx import has_app_context as has_app_context +from .ctx import has_request_context as has_request_context +from .globals import current_app as current_app +from .globals import g as g +from .globals import request as request +from .globals import session as session +from .helpers import abort as abort +from .helpers import flash as flash +from .helpers import get_flashed_messages as get_flashed_messages +from .helpers import get_template_attribute as get_template_attribute +from .helpers import make_response as make_response +from .helpers import redirect as redirect +from .helpers import send_file as send_file +from .helpers import send_from_directory as send_from_directory +from .helpers import stream_with_context as stream_with_context +from .helpers import url_for as url_for +from .json import jsonify as jsonify +from .signals import appcontext_popped as appcontext_popped +from .signals import appcontext_pushed as appcontext_pushed +from .signals import appcontext_tearing_down as appcontext_tearing_down +from .signals import before_render_template as before_render_template +from .signals import got_request_exception as got_request_exception +from .signals import message_flashed as message_flashed +from .signals import request_finished as request_finished +from .signals import request_started as request_started +from .signals import request_tearing_down as request_tearing_down +from .signals import template_rendered as template_rendered +from .templating import render_template as render_template +from .templating import render_template_string as render_template_string +from .templating import stream_template as stream_template +from .templating import stream_template_string as stream_template_string + +__version__ = "2.3.2" + + +def __getattr__(name): + if name == "_app_ctx_stack": + import warnings + from .globals import __app_ctx_stack + + warnings.warn( + "'_app_ctx_stack' is deprecated and will be removed in Flask 2.4.", + DeprecationWarning, + stacklevel=2, + ) + return __app_ctx_stack + + if name == "_request_ctx_stack": + import warnings + from .globals import __request_ctx_stack + + warnings.warn( + "'_request_ctx_stack' is deprecated and will be removed in Flask 2.4.", + DeprecationWarning, + stacklevel=2, + ) + return __request_ctx_stack + + if name == "escape": + import warnings + from markupsafe import escape + + warnings.warn( + "'flask.escape' is deprecated and will be removed in Flask 2.4. Import" + " 'markupsafe.escape' instead.", + DeprecationWarning, + stacklevel=2, + ) + return escape + + if name == "Markup": + import warnings + from markupsafe import Markup + + warnings.warn( + "'flask.Markup' is deprecated and will be removed in Flask 2.4. Import" + " 'markupsafe.Markup' instead.", + DeprecationWarning, + stacklevel=2, + ) + return Markup + + if name == "signals_available": + import warnings + + warnings.warn( + "'signals_available' is deprecated and will be removed in Flask 2.4." + " Signals are always available", + DeprecationWarning, + stacklevel=2, + ) + return True + + raise AttributeError(name) diff --git a/.venv/Lib/site-packages/flask/__main__.py b/.venv/Lib/site-packages/flask/__main__.py new file mode 100644 index 000000000..4e28416e1 --- /dev/null +++ b/.venv/Lib/site-packages/flask/__main__.py @@ -0,0 +1,3 @@ +from .cli import main + +main() diff --git a/.venv/Lib/site-packages/flask/__pycache__/__init__.cpython-311.pyc b/.venv/Lib/site-packages/flask/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5445ae6f16f369b506c9ec2d6482ec56972a9d9b GIT binary patch literal 4081 zcmcJS-)|dP702)R*Z4;qJHPBSNo_Yy>bgzb-IO1qEDNQ(uq&~BXcnz>i8MR*+$2Nh z7k9=<8a2`i@lf%?0}t?okdPLk<&U{kJd8#{DuR6|PeJ9WPn>gYCz&{?BP}P6DTB zN^%M~P1BOoR>oGTDmi0i?HtWXR;|2UpascU;0Zb*IR{*%Mag;KNjfRHV3q7LElZvN zo}yEdi@?)#TJj|D44si&vS#f$Iw!ddT%i@oQ@~YPl{^hRPv<4i0AHb3B+mjb&;`kJ zz>9QIas_yaE=jHeU!_+i&jZ(JP4X2>vFo%hdBJMf*XT9Li@?itS@IHalQtz^1zw>m zl54=LbX9U4_&U8VxdGgwEy>q_Z_pc(mx0@~Ex8GNlirlPV%@UW=$hnJ;B~q#`8sfi zb|kleZ`0erH|SeN`)7o{ZQR@>?OV@brAb?fQa|=x2mYtOXX*YPfclXAq|f{SF#C}C zp6mDwIQLzv&pd8Acp`J(b+*kNplN+OU|b7!O<&`u7cTW&?~&H)bIzP#6xVvL6R<

) zhD3db`4F#QJYcqG=>gO9AmC=VAK)O1w!X)p7pJ4na%PyE^-wqGGsn=jO$#$;24A>q zYl8%rKa$~qGu_q>%wYH2DAYc;v~8C|hKloTZe#KkjA=M0n&)~RGcE@E{;mvG&t(Qo zhgI0o4EF%ntg{*l1}K z^8=j+vLCaf(1lJ+jhY>HLng!Z7rRus5Yl{@dk5FF1cVbe62g&P2n~~u(i@#SosAyu z-_elKW5(crzv0@~R6x_3kc!Wpr=P)CA8 z*dBUs?>XjkTzlM9TKweEcUtj4t6};L1IilfK`AgAx??mBOv`F?S%Wj%-G`XzG-PRP zY;?ZTc|KIm%f>9W&#Y+rtZa>X0d3D{AKkyZ^+TU=f9nIiYj*W5*JIA6+vh#DC3ocdC#<`E&-2zl?guV6b!)4$&z$|O zADG=O-wfEg2R8&h^S0y$xvgnX+yhPPc#oojromGXpM9`TzXgr1!N>m%++3fLP%Vg3 z{i#|PYCX(WpOo+~%&v*JJcYsk$uG<Sn?qMYS4B6E?h3jEbc^63b$HkEB@A6fS3_4v z*Fbj--7>l+x)pS*;G+ESeE{x9ejTGNbT`no@jPtfedrn7jKgjG2g2XQv+sa=nSIB0 zjlRX+xP{~+ z5x0=s5pfI2H$~h+a$CeLB#R<$A!&)YT^1Q1*LdWfATbNc`yy_a^|>ub%tCTY#4RM> z7IC{QGCqp&SskCB@yPcDiP>eNxGzY|Lh^MHx64*=JSR3?FngD+;9Wst7LpG{+`@PQ Y9*AzbG>?Cq}OG zw;(Y&J25@AI3^9GTt7Y@WLJE=UP0wA4x8Nkl+v73yCM#tT_CprGcf9t%a=t42#%+N&&&WMsENB literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask/__pycache__/app.cpython-311.pyc b/.venv/Lib/site-packages/flask/__pycache__/app.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d2e9cc7e8cf9bf498920e57dc42f89fcf5d43f93 GIT binary patch literal 87102 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 {7Nfxv`Q2Zb&&X9=JAaU=vz#*1cdOvRPqi4dK6 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 lC#>odSEHH2Pyqa$Qp literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask/__pycache__/blueprints.cpython-311.pyc b/.venv/Lib/site-packages/flask/__pycache__/blueprints.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bb99247b0319eb9630a8ca7da71fe8a4e59458de GIT binary patch literal 32024 zcmd^oe{d96o?p)|X+|@WM$%{`AptEA2q7VU8jKKN5Wjy276iM-_KpVi2nLH8xo3op zGTgFTu2|YoiT1+AWY5m(EuAE6Ls;S0#$Q z)E3Dl`F!8&e%(DI$=sg3*{U?nQ}_G%eeZqW_t*Qrp5Ljiu99#)`^UpdC?-iip%?S= z@dww_AG#&!T}hD?*O+wEb;aePXZM)lfZX!3x!X%}N058nvboonr3ERg5;Y%sFsJy>uPfb( z`=Zp<`sei8t3RPo}ORLvt*VQpVHCR5muMrfB@=JPMki7uNDIU=iBvY3N{r#fe{m!}I+`9+ z@Ept}vJ>Ms6WQx&di5O}i)UUhHXI(CNQ|qf>LMjy1XPJ)?NBT}noX!NHSxwoB116w zuBInaN-;bXyP6nHs|hoS@+MR@t;Vj$Q_5IEEmjT1vWd8=q~A;x+vxe`_!#wOB%R78 z-pa!atsYRqOOglug1ry0Z~U5z!YnSViW3E%owvwv6;W$ilZl} z9lbFc7~!MOLt`>rPib!7l@ihwmm-05xUP7VMkVyN_lh?l1tcY^G%1m{eOG)+HKwdt ztw#3AzZgO<(rR42EnmlICR90n^+sYOD`O~RHE}JO0q~d`IWAu{$5VbYnY}J&uP3Tx zT$stRKnx z6;sxGGyZx4^Nop%p|)&dSmyI9V=iPGbyXfmtqFy}kWI_+u`vO!Jc75Y@sZbMLLG*T zy)0ibAUaVDh{lQ@^g#__IEt0&ahCm=FWY-4b-P$Unp87cpaczs$~sx}UQMURiWMq= zQ&UCnU^hjL)7%KsO^p~=erw1IT3S1z(r}OUA#X>?e3D=D{>VjwNp>obq8svUA#X> z?VgTDOii3=((22s>Dpx4HOWgP&+BXOXRrNK$S4sk`W|F?V|JwPNusmi{4CP zY?Rl_S`d|6^=4?Uh!Eg<_S!(-tCunfHS_9;_|@dq_^avhMCxLCLLEuG%E9>%Khq@+V)g}pwWUuJG0dW%S8VH{pFIJ54zg3Ve zjLe*r5o$B)r}p5f=owFsGoo4y#TA8#Wz=^@KN%(Ms!+F5k)0I0K*1gg7=he}rwlPe zf=-szZIp5t!KAzt*|InARVvzsH3ZTXl|tcr2eshFLT$sM=Xum7vpKU<$aFsL6G)Z}ydrt^B!`5Etw_ieHM0rcM+Zn)HT_DL+WsgC;E~ zw^0QlCrfdt=34p ztn4UD3ma))Rd$u7)fs7DQ+Ai7)f;IqD=(I%H5h4El)kdG2>SVo(qGokM#R6W94L#A zBK|eyrLy=Y#D85mTo&Jq_?U96EWQQt!^(-W_*ICHE2qlhTc@PATvysa_^+z8jN(55 zqq+b!GeMd*NV7$Bd+;)n9vg#d2;H7kJ2gE4rIqPpX;68UQGF;SIbQmmvcds#tCrAp00hE!;>$)j}=1g^}RK7poD7 zQ$}gFq6uUS93bPf2qaA20@P{IL4fKgO9oN&;4|9x+ZNB|Dn4it}N4Go9+p5}L+G z$ZnX#@HmD-7zdZ0b2HhXuVTVw$dk5lwuErBZvwu=#4;1)UxD^ zn^l9}*rprkCaN%}+lD4qA({bDDo}GW?TO(84B#7}+!+g$Bquj~LaZA2C^<&ZnnhYL z45=|322~&=!OAToAL!tv3uiLcL?R!VBWXBp5+1__O$Jh69z}uDWwK@^945{h9gqm) z4gn%wsCU2sVOTYID#I%fK1>jJkVZ(f7>y^#dgKh(IN3}a0!L;%F_Iij+E&EPc#4s1W~m0V zH<(LruY3#48r)_CICm|f^!3Txd$;#)6Kx+hCkiB;qwDbS$XF62{2FF%oDj-ndvXd` zfnE-rISIMxCYn?-7M-F6$BM>SK~%sP8#<&ScPgu<$Ee#*{>IzDUWFlR5fP<4!^6x} zhDwZv%KF0y0(!HpcMt2!u|aMOBo(L_w9P@W+Cej)HFGObI@5a|wD?RCi@>lM)fySu z3PYMoN>s7dT#W{s;)cf#Br(W+yi+>@aiW0-v}(gzfudVgH7K$CatgigyVcu1*ulw_FNr)G+BdbCnov zzU5*TeL%@CW(W6*H<+RSV3b(wadj?#u0M;>NVrl~E~gIXY4LSZ{~Z2v^vLLi-^)L=|d zhfG(98%;J+>QbE$m2y)I^@-OKh{c$c9gAg1%_rP9uDe{bCY5`#UaU}I3;sRCXGl-| z`CaKRS4n}I>B@VR3;yPLe{-REePLB+p{<+l=-S1g6li%uMuwjWO9RZu;mD%o3he!H zeVev=Prm*|y`JnEkApQc9aHw))rbb#j34Y zfsepzU?|LkWUdtD@$PxQ#3TrOr=1Az;AB0KCs1urG-K1PbFv4h0V$kb(D0Po$PX>Sq>dnr;Co|j`CYtqp6J%J3&t&k%yUQXyEY2Rjy}%0SJJ>t$Gs z>JGVPFT-erzdS5pcjDzmj}^hApLi-7YJk@bHL$c**DQKa1FMGPnwPZ5XH}N<-+^m{ zP5AG6+J^@xt}R1%OLis=^Rj#Lzg#f3lu0WUnro>dx|BjGn6NbiBtp*&`jeJ zRhOu@$Sx`(4u--cuU?zD3CyBrzN-sFG1Meuf4XctTGYZg}< z&54Py=#SI-5C-2P`EB6JH{6DIXz z7`c>-3)ORR;wlrCz)Oi~r=ixUNrey=fv*l!vq4A(LnG{wGmlDd!Rn~-;ru`2T&5$=CB(oYRync4qT*KToZO_Sk?J2$X zl;%IhXOg)!(1whIDN(~v7F|$ZiSU5rCTxYt zacn>nB_}ZvHp+=q5{`VVb<0LT@Q|gQoAK}j+XCNApcHFZOuZO`B4C)@Fu;5mMZ=h9 z3nq+qGD|)&gCKerfOsm&W$M=vm{d?W;czNwu8exKBbGX3b7JW&PyIirGxHJxki<4A z)cC*)cNE-A;W(17KdRRs)j~&^Pe}8Ef9v2G zCEi_6qtG{7y?)H&;gC8aXs$@ynoYSUCBWX<}w{dcNRhL{GsW^2qR z`(NjH9Fbl-{VMS6PVi1B7rg79ZcJ6MdGqFigfVx5S@LN!uB>c6VMHQtOS#bVwc%{D z1Vcl)5XM_ToeR=<-#dez)S0b4Un{TGvYu4msmax#Mo~If&1ww8#fQeH-mDdQ#IqA7 zmt^FHAjvP}70=7$jo9*v=VkIX+VYC$W%5RCdByWGd7Er`#dB$1jDc|f$NX2{sYP#V za{=eta7p)SmZdn2s6!9|XZ?4=NF!p*t{b$!%`Wv`E_`=0#&LTJ2G4V65AHOe#-(#MmE?@%B6llubvH=wVAq{UE?~WVvmqDxW?e3#cqfr+ zPhs!%N)xTPR10!dJ z|5ciu{ZX13Tn)?czmnWWAEHJd8qf!foWkF!4;DPs2k~a+0Y|AW8X)Yp#J>XxdjO&uH-;D*4RdZ-LRuMiY<{4W5U9vEkn|(i@DNQZOQ~~! zQ)*;l9il`94)c!Cw}kM$q+^0;&k_o0`@hsuVM4@ZN!a-;Dbd(nL*sl4+6Dy|(=DNp zf2MS1vmZwjNk= zuC<@Fqj#sHzCpfACHg|vjyGX!g*AT!mR4q3yKU`PVhc+YU%GmyZgIhOfW(ycZPK(k z)l3WE8iXn1i)N_TT;9hpLz#stn^r#;j8Y}1yq{$7wdRW>069tk{rdJ2N?}*W4AUGgGXiW&Uv;VjD|K`CD4#JLEw~GbeIXyG*AX-?r zVYd50$AgZC%EN;X4?em`;mklGvUb*^M>-ZF-Sd&|xnudrPCc?yWA~!Ztb$F}pabbD z&?1`#vPHZr;jn@9S_d0o7wrAm(SvTZjAmatG0ykD@4mNzES!$kAQ14@R#~n2t=4jG zlnMa339k+0R?~Pc1`=$M)gN(0}G z`d}uJ+-p}^!JlqB_%QHj*MpO@*+q{dg$*RknpqTs*@l7W9Z4%VXGNiLD9T~KQSTtH z)6~w-M%osk=*DG&iFW@8CSPOJ3ZCF#Pw#^xv)zl8Qp;)!*22Kx!obk{z)*hRvOaK` z!TW@|^E1{bkE0R>KHCeW_)-peV zOtHan6xWE1nn!HSbGSx)qs`CB@-rwlQ8Zh>jsvopVykdPAtwjN@!SmCpyPf89(bM< z{icVG+Dly^BMDA2)e}qfU@~bKGGE}HIEY+#;HCS3)wzCr$C9! zNHLgri#d^9i^a3WMt;H+)QQ(*95QX<(L{_L34AYxsFL~?)$e0{=jRxR{IDZ1n4pAG ztS6@$IH#q@;P%PAYuJeiAjNph5I>96cxFC4{Ip>RufjWx6GT$=hp|}8u9w*IRcDZH zcf2qMq>dIr5ajgdAc>28Qq!7uU;p*jXSY18&qsIZ(Opx)LZtQG)4zUtwgM+o0{O@e zJ+cGG?&?=-wcWU91N`qo?T-1{9S?WrYxn52d#1dPgS9g|?;p^D?YIl_`VVU6vbwzM zkyn%ZanFp-jDEUh>Ud%E&WG9g&HJ>?`yTW>$l^cy_i6pq>Hk{aw&-@(bw7BSD04Rp z01FnK`O>+=dSS^=JYL#9M}Y10>YBd{NgFoV`RJpIKm7W_{tNT_FXZHCL}mhZfz zBkZ`OcU;osOB#;GtlKy@@<~ct*RSEs;o9|6o_jSj*wbw*bZjE;k9O?EErd7Bhd0cQ z%<%>ETmTK6F_Rwu6cUY6_vch0vP$&>D71r&9~><#%D#8hzE)LQ6XcOZD0( z1SG)4Mn4N`q!5a)4P16<9s8cJhefZa8k}i~ph{Z1USIRV!kT^aYxd>W?AO=qUzCEB z8Nqj|W;`>O3TxUQygsAMC=Wa4zA^WWM-3Ftcz)cx{>PE#MYo_nOg`MLg}WcG+o-R5VPW0A`E~p9 z>-OvG0D_A^K=7TK8UKTh!q%NsV%_YE`EZXG?s*)lpE@?POK<3z8_|1@LF$~r+5sw9_}uL8}#tzCq56283Gy=Iwo4(z-!zxm(jPL$cIkq zp_5wZq^NQ0!v=l(nSAK19y+Uq&WiY*4=?I34COZAJVqndveCjH)vdJtv&f!;!GyH?u; zK<`)TVR<3kIUnxCs`2Za_U6NVdbm$xccE_mZ{ODHw&5kDf)>1%h)gdW#M z?tMe6-8`4mwql*`e$-#NVZ2s@2}PBdJ3Dj zezMhweq7t8)piu*F3^CPYE(@}&uY6LR%_c%K900lLe)S%vQ3X{10jj*ezbaF@7eji zXFnUs@4cY!y^xPwSoBDBtq=P1;Z0h26Hf2eqoK`(?ibOF5m~5<>UHf}-IhZ4HobeF zk??p^&(x`zJNeKC9A)E6^Fe0zR6ev-4{g=hy|~vLKhC+KCD@J(K5H7y_FkaFG-PZc zA9>Tqvc=FkV#4RuB-_t|^bG>@gf5A!=2eLYnD1Rre}sp3T<^Hw@x0@G$M>!@?N%EU z=poFZ5v19?%H1BPJ?bXAOUN{ig*lBxYBOr`SngzHb(U=8(7x*|$$VwklzYlI<(+a( zc}9J3Qt>;@Wrnj!WjqXkFBrB2IZp1`{3NPSxP_S0E3;E2w1?U^+{?`*#L0=r(E(0& z+Cu2#qZ4o+!wD4T{$oFALd=d-N6`{AN9=s!Kt3!3<*jm;aU%ymLE$)HV)>G@Emc-Q zAGwB>zwEfU>o4i`j3xO)C_Y2fe+~|oB?12lw6wOP%3gj;fL2eH)O-e zC)U5ssM{+a#koL8(`3_w#mBI;8YIN5DaPBfyAv4pTw0uc%%#CR8P6A%;aOwC$o${l zOv1Wkhr=OT3l}u162t~13VskoI4qx>qH9#8y*=i8=2(|PN8gR)@4AWb&*G{4%E18* zUh!`G-ahtn$@$Dp&Sx7@1fNH0q6LO=vOZPByYi7oC5r*eX0u!wYqb~gz)rp1aTz!OsziKORDW^!sLZta)43g{wY$1~OnV2ryN1Ct%`8Dkx zub8&EeDot)Sc`$?ZFnyRZX{DT;`mP5tzso#iW$a^fa`IjTdR`WugnEmXX@o*Bq#fA zn7;HPw-#qv=|2H7Jza+eX^|c{ICbY_{ z(jUW@(4rv!9I@P&&|IDBM~Iqi|6CaV9j!<*Rk0P>>4o9Pw?EK8y*Tb@7hv2a1w9VT0dp>^0 z;s1iT9mi=hM13jzP9>2Gtgf+))lo0h-$klpEiq0qY3)1rI%ph~vDS@XYX6?)?bX(4tk_hoRHO5U55dCW?B5if78 zoiZ+i&woqmzc7({kZC>3@{k`P--;>@Z>|A#S}G2>$QPyJs9^x$;10y&m@STsreuj* z&dR`!mAc9;_S4MFJNZ8QScIX*J9qz$Ph%MetrIw$Mqj^TpX2Ufhb`GzPxi?dd}f0_ zy=@(uD*bp-iT%JdIv7^Fl6EcgnL|+*7Bf=LOAl&VYWgxhyV5nuX+v9jqXVaEL1jM1 ze|{M*V1`n!{%ypnFH!Jy1RuH8-=t?!kNKHlLj?LQMA#J%qk|;<8zX38rfDqiA><*V z4aEZn@Pr=Swh-MnAKmxp2)-K|J*r2KE=14FN6&orm3;J^9zA!LlYfS^fP@*)EJ(N+ zyI5b|wEZ|!dFn<2V;ctpR(4bOE`-R8&F?23H<_6ckWH-$n{eT}DL>;yDjgyDQV{if zc0_eJq!@V0;^Z$AO`Wa&3S;Rzm;?(;)qjuIa`fC{lhE0x_E*Ht-DTLhbs^d}AMJaz z>r*(29MPjk7NV!;qo+SRl#dST(LpWo^8t^<)9Wa?v;?T z{>wtjSvyjeIz&A`UJ7%nK}OAw8eA2wq@T0t!GG+)q%Dxc&5ep*IRZNMJg8|Ch{d4V zP^Fx9zEp;tI~Jn*=cD@{DW4wBM~~~#;|tNj`RL$hZ{(w2(W75k89O6OwK}=RS};qc z_brE`U(rIwy%LVX1pVa@&fm7*oUSbXha+m5}w<(1B--_%)csD@WfNNwDAI zcnxkY_z{<9CDwR{6DqTMIAa{bg4j!2d53xOAJ}o4)yF9(xo6PlTnU|@OA@euw2wB! zo|ED_nzWFZ+rQ}?=?eCRek6a_P2Y81ZpYWyQeR4F$F47YGnS_6r&z_M4j!{Yltr?* zO2ypil8>sHVz1lywz|E;T^=s=5)yFHm!?ga|9%TElLswYNeF5$ZmkJn&#d1E<)H@G;>dJQ>);kZ|R|fzi`B!CtkvPnEkxjeg z#{`&N>iK-YzD8g$nH+GiE$+7Y5WX*V*na0j1A1sc3k{U-3J6qC*%Q?SAep4jfFzKd zTixN(;j(|2qcrV2fk(A5t0lh2^4HqrrZwhReP5JL`MdVjxwPN+^R83DZhkSzXqm>X z6}$9Gx`C1Tf23f38%=+%=)T*zx|Z%``Jx&nbaC*WoeR+e^U(v3vY%eaM^EU{6ARIE z^U-tKd8n8d^ymfq>M9rFR}nrg-S}k3^MLqu0?5=g?Of=B7BcRYxKPuVg}@H>LLD@} z=<>X1YuZD8LH6Qk@>dvHr=JH|d&)7v9L{nS9Tx=GG=gkji1yD%`yUN`x+5Pwrbmx0 zM9j?4*CP~rl!9Xv ze2szt1=}gOLP3y%7zLvgT&IAz9y=w(d|%byqt}lp_}3Ktkb-|p!H+1=DEN;Q{3i4It z*ZQ`=yVeMvco6sYD?B#L(u2O8I8hbSMaas;+~Jv`s@)<^I;s$w;l)wk%b z^wrVO^FX9i1Rr=aiDmi)(gRer8Hn-}5vBQY2WfE3K%`T|Dwb{*WtE6@tNiltiC$U# z<5qTBG+jOP3rC|9_(ULn;YcMNtmsZ>R61EwbY;O)W-_(nlmtu)QT!6eCp% zKLcz0!mEfT%3737ho=F4nDo5)ORORrk=kO^%;xm#We&+!;&I33HrrJ%M$D2!HjgUi z^Hr?JAry=Q{ZfW#jmUDb4GEX&tK8>pKMgCgFv`yMSs6Xtj1qj3x8VtADfn+#9Z>%Y zuS7gEq_g4UpDtHHTBkYh$5P-f`&W?aHS;b=>ow-pz01{F@UGIF_v7Z4_o}pxz1sS|M~8lRN?U(SZ$7R`jfMKw znfCi#THBU~7xWj-X!U3F^=I|^vv+F?4Q(^q@9))CZ+)ohd(LSM=kpEc^@j7B6kefF zb#&@0_g;4`|f~^VJ9S>VtQyaM10+8}HpNc-PIX(>I^RSyI`J)7-Kfn_IG5 zliIMg)wpKn(EXFzn(dG3aR5z=T+Bx<>XD0@R9A?sUN&j@4%Drhsk`5zwRS(;q3=AQ z)t$`Ooz&}2-mNLLc0Abr-rjWYFl_*)d9mt(%LV$sbohkD|ID6x Y!~M4^U7%e{hco^sEahj*q%$P^zdx(p8vpA?iU)3RO^^%iYQv_00?LqTj%qC^6m2B-%H z^wJ(pOldh|dLoy(v-S?NnTKYrNwk}tEvIfbWv^!@&Z81Q)hQuJbjQs`RXbN#Df(pJ zIj+0pe*f?5Zghi`AGxZlYc@ah<9k2;@9*C~4+Ojdj?e$$8Tq~M3c}ygjegYd3-Mu( zOAy`?WI+~3g)#B8DAKiU)OOm&e(k62>{mK1v0uk&2m5uNcCugBX&3u-pLVlf&uK4y z?W4Xi|7kzVOBxM~Rh_QV@(rF2;=Np!XZJf zx+ciMMDRjXkMlFTAiRrzewrOx63sMSIHrStK~4lHS)`H?KScATDcB)9X0`Z ztkYA;_2)#nL2gWR$PqbmyXj|6Dhqvs?aln>oLY^^_wvDb)kL_R7XlaJp%VeO@gSpD)-^3(D& zUlQviQtkQ~vVK?3UXV{=UJQI;-p{hKj22PvBF%HwmL;CV)8}u0<7W=!j(>hs)ba({ zCZ9$fE$gBp&NmU~#V?8T66)}+FNrfK(_GnI(b_W!>B2s}b{F>RSAS@e`Ij-}*@QM&dI4t{$g zKB~QO4WhC`gM+^i9#Zu_f3COZ#b?tACH>;z_}P)O@fTC$i6rmB7g<}npHH0aM)kS} zCNe2yBtH6L>=N4g;_;EQFQzdB-Q)40i}7=b^o!_~^u>)sqa(5Ls|pcBENH<+x(>mV z@mG|d%ij^O_SBl?W;d6x9tUW{drR@KVR5m@%NQAmoIc zC`;CvJ!#8;8q<%Q?Yh%CKNTrw8?uSQDPd;av~yUL9oO7B;evsm=S}(Rxd;_7?Lfu- zq&-7**N&XMVvUO0DsboQva?Z-h8lcHDpn^Ynh6?71lfhUy7l`%6lAKq`QG!6!&>^Q zqU=S_&3=WRlQLmFXF<5Y=w7d5f30Dp5k2@(|(P9KeS57(B#mL)q=8X(vc~5 z%#sq*;;VwC7koJpZTDBSJy3C9#bO2D@mTAhbG&MkrAf!jj?3a@;fnnQ;j%dMh9&>% zikvEYxn^lEcZRZ;4~<}zMB`Du45K5-bS9o0N<=f~N77M%nFPXAba(`dICDOM6`jsR z$5ZL_$l1|^H;Ti&>_?I;l9m@1y+QyYP0%5sLyZ_qrO;3*RR}t5B|Gu}AT7g>e#;tj zA{Itje7Fr4Z;EdT=dg-iiePq_R$@-PZnLhMe;mq*Z`fvPPYDW*9N?gLB(1j((99Ow zR1z;KG*i=9!a_7Ur8MC8bMLOvk#uG#H8#FGyOLTyNUbL58rwCR8j6pmcjH2jLezPh zn1j!zgnZR8e$GDgs|)Yfyx&)N?5O(KQ9PUew(*Wb5<)WBO$UGohB5%5V-us95g>pl zgJtGUO=C>-(do##J7Q6Q!DvUey@w!W2aQg8JTWvfe3kY6PztzUC=*R36ESqHcSuPP zI-(wSkHs&tt8B<9cQ`%-Xn7U+1v)GRZSLrbo}I`wfc-&(pW+idX>!0u3Oqz*1$kX zU;|ik0ma2L8ATy>kPwVKGL!*QabAj#P9)ML`)DG`VLf5Dk_+r z3|t*g^eIY8Db){BYZLMyH5Rx$1!T-x<|;Y)>@InzIEKfRCYI$`JTr72MbSha)EZF| z6MTXZe5chCjqYWWtQ4?JEM*J5$A7v369Y48(JeR{@>0F|TyzR`U5kR`sAs{n=YCb~ z?C{*ktw^CNrdGwK?GJplvqN*+3%-@AZ{?yOdg_bey6L0zw`j*5at$6AjhQ&N_U(=L znl{~S+Ei%TqBd>8i$c{gwd&Z^p$9JS^p00@*K)JpzUykpyBdnYy4i2fWb^LE`yT)F z^VeHuTIR&Np2obV@qSgyqRkfAP^_uH*|uoM)uKSR>o?urSiWV?KDJ9i?^lYPb`Pu4yYax6U4=KQy|g?Xw5rmPNr6KpA>)zdm;B zJB9iu)cPkVK~pi(_@Hj}qRn30eGAd>!-Dtge%)5STWD;1yKT{-zg*a`t$f2`eQbBs zhdvPyEP928#zmi_rtvcziyo9qzX8<#({{m!CfGd9#Xxvw5dGt6M%UnWZP!myac7#q(}%(4-k9yfnD@Xo$A>$29N6gi^+pG-Eg+N7Fe6KTfQz>TGoZX+ z08J}0l*KYOn-o1DQ(lSY#0!iVMkc}qf|2Y1qA^I12|Fyp37I3W9wm{PP?9}VJ7pq)ih%;Is1J|%JL>3nb_&V~Ax#gGsP zPVb-IzZeukk(*7p@Cm`1>EvRyP#poB;BP-e6es^nSEHmqtlcLHf9^r>foR_+*@ukj zftN(nu}Sv{!ZIa13Ch(Ym}y|sR1)Wnsf5(VQ86{`ws6aREi;;Al=8{hGp1Ty@aTD4>!A2^_A zpNKyYCq2o%sMmTu1?#2Fs8@ISNo6ieIEf(ZMWXl3^M|t? zzz>2t+YtqnCou-dx)D&mKfC^*MlqrS!wE=Uz%GqVfG;|mKy$bthqbRK z`nedh;AO&(jFou|7aAi|XJur{_&Fz9rxTc&dYzderYW5%`9~qyP~xM5tZ_DlmLJ}L z1~+4jD4u55GJ=z6)3aAK0n&2p%=ZyDy$S)ineZNd-WqzdSB?O) zy3=^eIw9L#IiC!!ho+S_N|^n`jPyjajpgW!wJuM(tVBdh*3YOAjXBHuOsrXUi-{-0 zjN^<7&>BN|Dng?{m~IJnb5kRjS&jFGBv1;G9CEq7dX%NQK5IpiZwsfV1SLX-yD? zGlNp%%D7UJ*n?;2z4PK_R-{DztZb&_#IvPI2oW_7&X|Rkt`p@n;-x6T-(tc(f;n?L z9FhCM(9G4jh99^7sI}18sWx`rapr?N3c(#Jox7%`Y3Z~3zB+IVjz~EG|5Ws!oV$|u zpXBGqb{la?2o{3jMTgB3S+pYsScp%(f;%+3`W^e*?t*Kj>H?G38YQ5qY#X#!5FIGsk$GE7ORiG z_l*B{`>{NfkJqX8s0N~pvczB z``do~B-TZt_8GPIndyVm2S2+X1Uu#MG?ar+okDnJvHHaO?tJwLewGVd2-l;zfrdpF z(ol1&gy4!t^$l@I-bHkK&3*8um*z5s;A%CvTI*zD;~X{RfOYcWTTIbEO*?x5;I*A-lCstXKZz!6@wc|EnoP~Gh6IVm6Nn0F$;Io&(m zi#DUVZclAFxF24BYg-|_NezS96$5p}>e>gPD44*Sb#qtHjGA>UC`OuYJ_Qa?yJgS7 z0n%U~z&J!|7d=v-metOK5~!9DAs7bZ@2Z(yH9Jvotx#PnP=+I142Gt?54;VFHqq0i zv6{HTJKVN)kT`(fuqPke?ZjvzpdNFk`!Lz3yB`z&qHSNT{loh9-X7t@p0)#x_Fr$R z?h}RIh~B;~`)_<6kw!Z6--Tu$*4qPw64uJCF!#~3^ z0#}Mc^rMXR<_(;nzoXxrV8sfPk4kM|kuOU9BFdN)Cv7=sH#9-FEhj!QPsyB@eqC83 z*{0>x_K0>7?q70L<}wN4=A<3uttqCdZwS9GIV$sDtrI4toPFM;RwyT{6pn*gD!&v= zr5Qqc)9XjYHJBuG+?)Va2m1P5V@$21m==@b%%x1EoTgm5>?q44a>7M6u23v28+YDd ztI9bEFgHQZSW1UV#yP)yP3^J^f9~(u%cWZD3JsVi`}cKm`7q>|jD%%!^2;L-jb5J$30*3U0?Iu0WR8{I`E(-e6#*u&C0tqE9X}iYC6=Kj#rLO^-XUrLU5UQ zH8+(j1|!qb1DEI8<$JFByRP~4z`PZ!6TUQ)|~<_X4lTMR)j~yXmgGX>MD=9aY`YygT}U<@555m)|-2 z_PHOA{%G{pwmT~dt$WngJ%!+2HMo}mY^dn3fjrO=B5dNjc4bz)_MKVzuB$2UYP#?C z&A49=-U!Z#rfe5{Rj=>7v2*s=yoA5@c}b0|Dfrf^zO{L2Eu%RHhRm?e5Wbv6x4lII z7emgs6nct6aujT+u__rGItVymf>9=V9HUWInwjNKXaUNNg^8?D2ZD zHNA#Pg{O+L_1WnoZ8(1d8KBRU0b67Wv5ZO&1th8}c`{0TC~+1_?UHvmr9k^I2;pMM z#n)S!X%raY+9@d)DHVweOCeT|!I9xX(ENi;InPMwH1!&-O1>z)r03#lBZZJd5&!AG zLjdB}2KwhdsL&@0?l#rkmS-m?Yki=M1U&$y=MT>8y1sj6_Z;*QEvj!dkwjq-oFGbS zcFr@|`%Wy6nw|IC)~Rh<3vJugw(TUe=TAYE5b=Wms*eb$LOV!9w@?)&!jk7fGYH(}by_HEjUk!$YAMRVT?+N<{JtD&87u>%_x4b1_!jhgF*Zfdy zG$~;XAdHHWFra{Kq;1STDPfVB5Kvi;DNAO}`lA;MkeUSPixbj1WBFqVIZ?KOu5Y`n z(^Uldv^?6gE=8b6)Vb5$&#?w^M-Z3*om_(51vF%XgP*&e<_In8@^a-}*6V#fp*)fzFO(~t;QjL;GkBp9xSqia>SQ#bvWi29SC@&#<#D~quMF?kx&O;_X4!lWo zxm3mRre3geh2ny(8v%|f*@rS$7!w*FQx4*VlBIyMtHdonGJMf0ue^!~ixlaP5KIY0 zUp1zlBRC7u2C0o8Eq7NyhLW440t_~|U`{j)GoX?i z7YW$EC_`wzacFZ$d`OJ7)#%3qBm&8BP_CB!u)mb#8raiHumdJzpis$sY6$Fq<_MG- z@$UiG97Zjm%t@WS0NR8IAsNI47fUQr^QL1_s98YC;G9T<%o)8(DrQC*B@;u5bUMz7 zsgWeaThQJlct#MVjAS|}4dfK;U6Q5M)I9P?8q~}XX?}Dfi%l<-b|eXrB9u0XsMdAq zXlhuKhAj>FoCYR;;}_3RM3 z!1@TVSbKGrDdk!Eo*|eWrF+h>&N!r`CdQ%9f*Sp5Y63JPa!e&5%a9?egieaqj@ILx7VIA=1xXg7p%J3(KKDXS6U{~Yp)glgVw68$k%^Ho zhQzSnjKyMIyc=H9;*_e=7W*+0@T5jdPA+UMNtDl!3CF^&MpOH6nO{!K2}A|*BL_+V zgoSpHJaEvUI)GP&K?8`%^v=ka0MReReo&M*ke1cEB*CyQu8@EdFo~O!F_Sl`B&8Fh z!{wMPjuoRRFCtksT%NNrok)fSx{xMR4%Aj9L^n=Ls=EdFrg_b@G!w){=LTGOimhGr zrn%VJO}`C!cCv-agigydx_^$$fg4PC;S~#(fYQ{&aJ^CsIBj$ms$?8iI6WyQzk_r} zM=D3n_G4wDjL5KZEZJ_gI+Mk7B0)~zDCv8)GI_+@@Lhv_=6LXmRNvh)601 zUkn4E%*Yrlq8OaHKuQDPN!b37fR~DjkAf$YuWFf-9S}e%gCCR=#JzkO>Y8YJ*q`&*;^byM zRH+Uiko3i9cQ>->h^CnFXIHf2;PHK@jt%a6`st1+3@t}sBtzyvhKh%&XyVZhtrAG6 zL_2szI$%&nL^E%*X1*HbsvB4%#X5b;P1KVud$z1gHYK6R^oZC)Mv`(VGeHBzkD%mW zCa(Y(Z_=YC3J44-#B-K>8bBnzw30}0(?Aj+v498t;cCqJG{Fdf2e06-R(;KRUq>-q zuZCCU{i_yy!I?dI-&)85-`e=YjfK!EHMEMvfRNm(LC9VGfz}6+x|@gRUb=Na?b`eP z%0lFT8aeQh^!}wn|=d*0rqwY1JUpolNu#o0pokFkB%z8v$~K#J7sI6GhlPov2S^ zN1E#0iq|WIRDeFV_-AP0^DrSNovBXC!L9``f1D%_I!3xMDZcYct zkhqc4|QMZ7~4m0D)A%P_4mC2MuFC)C6osG(Bt9z`&i z%|@&!avl?R=}|F7L7C0dBwunsrfiZCm0w%aTT7(PC_u|jJ@$3!98mfnizi7xY$LM> z=y!jJx1BD9XpT~VFS$WZlk;Uy@Sqf6=9s{kZ0iKKwA6-{WRRCq7ZYHJ95AHHTv15# zr+k9~h74%0m;w5^rEke&Otx%0%Nlb;ofe(0 zZ&?U7PfyI`=JvrRYhL2ESqN`IX-H;TdG|&Q!YbcEsU<(L0k9EcYgeJ+0WhUzDgO`w z(|n)N1EE(nb;>yp3av)C)ds<0Bc6DzQN&PEk}FE8nEY# zw)W2GYnlLn0ZuIEfe2cOXZQa=C|>Q8$4RC1W{sT4D+ zH^9XGEwk8ZOo151hevVon(&(Vn(Z~|E#bOt9`{QR+G}E^yKhL-;JP1x1HkZ8n2u8EXJz#;F1Z$X`4Uvm) zQWr`}@QWnklYmjnTc(u7Y}f7Q#OoT|y3XKMrRGhCV-l+pU$qW4SxYW$`hh@YOSTN1 zh+ZxEsp}w*RS0x(Fg1mPTYS>;&aTpzO-#$FY`tSZsH?QX`w$x|ycmRCu^8yMA6YfO zuMkRuWABlFrWKcj+OEW+jMqEj>ydQs%F7!cs&A zw(BSVpR6@GF&qcu$RX4@k|zOHlAOrIFY0Sm9}Lr?ffRK#4QT9zv`5QI`8hg>Oqj@ z?7$;XQ01pR2S(81bU@{>G+=e${W68DJ`ZrH*Q?>+SLm6aKYNOi%F01JQWzUVY>q`^ zV8;Xeiw~d11!Rrl)RFgmEq8q_@0>39 z)~UXAQwNI8(WwKf)Br*H)N$5PSzGtMtb>UOO3ouEo_^}&K=xCjmJI=l!GQqz>PGoG zb|t(?Tz8i)7a&bQw1exj`2L?*^aR^2$^@psvGFK2v=Yn1*?W>OFu?-JJ!8>+LS##r zh+*IwdP<@Q>~W$Wy;gKv-YTJ@#j7gtZGu%|Ju!~88xX5_*G+0jt{Vv;SS>;F#AoZ8T%_VVD$;X932m1Cu zd#KY@ijd+3dLMKWn8ra)uQO4MLfMpD2l@`~d-nK1$){Zmp4j)a@-6mClO-*kx=x-= z#pLy}$;*U4%7@6{r!;*@@&n-Ggxc?3V9njYn)$>}E))Wr)xc)b{{`}}=Ni86u801T zg{!cYr;}`-+O&X--lj89Hm>W=N4L-0=k0e^eQ*D@qtlZGX@zOVhq}92(HpzFlPP|g z4W5E@kUb^q4Q#`+^EqG)zh$tgKQJ`n!+(T}GE@LGUN|asUi7TddfnScXy9C*$F3d35A#N#E|yL4cA%Wi(D`e_VcA zpIs#%lhyGum&_XFw@6hnWkQ1}e2^do+vZ1lGUZ<)+CQVILrarQ9d|&7eNrT^pNo>q z5h=QB?z!9Uy4&X61$U?F?##23>%d_KN+^a0_p8EcRkY~eU#t#;Ra|so=iA4${f+N| zqge)%KC2yH3ga8KQDJ`7KD!-2Hj(vqccTg2)C6?j zFy5Ek5T6dFF2=8Bj~xdTT~;KU=El8DAWdmw(JvXW7yy}+!M4cdpx6+KH4bgsi4UnV zBoZ_G58$dqrcPWTw=%I<@LB+TVKwoE?7rrj`?Ql?g>dD9;;~JRvil~)bjvH*b;~vX zY0tE9MLg}r^lLA1B{ZY3?M3#cjIbUNislv7MhoR*##C$9== z#*@%oBEDlR1zn*=X&c?fxw?^akO!JfsUh<3Cj$)91;$w>a^e!4Hjp}0PC?jDQY_AIK2HXQOhe2C9jx*sH8Ja%4E+gZMwKZ)AfXYg`)Oj+i{TLkb)m9L zhP{~GKu?sg86_fmDXrl(wBp=X6v6JJVP+X%1or_?BA+v7x}r3mm8esDoCsO%$dEFA|7n>q_qqp z6_RG9ESIL02muPMOl^^TK~*=$HW_6c0WC`Y76>(VRe)lBl`s(!#*?Po^0ULpj&0od z@`=aBT@y7A^p_&bt#U@7mK8ar5Jj>sP32zz&~t6P1G)qy{<$L)+n2mrR`m=KX`>%> z4T3^^2ybOvj%^}pa?VGPI3R+oO!+v8yewqTq$}rI-ex>wDnDZwM+t(NsvWM_5(>h` zt~4P>Q(CArWM-pD;)^sN{t~zg|ubme7L%<4#oi!Bd#pqQ5~4NrbB%l`VW^ny8)v zPG>A*!wk=sFQ@&{X<*zY43c7y9n2)n)n9Tlb|TIA{Zh3i1t;1+1E`k9429th(REJOUdr#*`fF43{Kw*P;9p8It)jd?3lC>M{|?kqL}S024ICQwnG>kiSzBl(ed1 z1>B*B4v-HCg)1#r;(=*h_-NH=FrnllFHibSfZ;^rwhH2#OoC+l49UX%1V=i9Ik`J5X@+Z^T?|Xko!F^11AIrOsEw~%L@3`)oaWTuAO?mewY`Jl7 zy0r!YKNp&?^JgYlY+lRt)0(-?f{#2nc)E-J>U;i{yZ)AUzG>8>{OqNIe}n4ZkoRvW zKl@g}-=+Gy^8T)c4rcnZ8fKz6mzOm%4vq|DiCw>dUw&|g+APU2+2e>8L9t@IT+BMu zJ|<0y;Nc|P38N0OdRZO_$j*@(?7!XvhO*p>%9KSSB?@@gW?*&emeT@+?E zu_bB5)s|$Z?RRLl@H-L`FpE)W%iSdPAUmyW6{B=?VRag&CnPEyz?QwgrTE(sl>GXF zA_9zYY6|sXDP-_~gL-~2a7+?%aERF!Q ze4F{X5Nf&?>bQ$-VzJ%WDOL#WQA2wuKbUhMnBH&9yt$J|E%8DVoY=p)nC@1oVS&7MqBz8ji)3(BD~ptwRqHfhia3yX7$}45n;Wti>cw z5K594kmWVZW(;h_5|i*Cl9RrQUU|}y?1PBIz-w&Z!p=#j*(9uN1`Yi9h}}NcHo~0R z_Ksb)vxSA8D2qcxf%XF6`wke^alyc_Uv;!#Tj}i2y4dan+NACsDA~c%k}EEtvXX81TxU@E zFQ|j^KO-nHGinVtnFP$tM5l&gG4-?~&5XFKNNkJE2r#rtlesZ`Fj<-PVTciXoV+PA6g+wg#&@5%2^)zjK|LaZ%t}T9DoakK!R-XQU0anag zi>!-cd2mtb{J=Wxf$bjQImS%fSERwVO6UQpHA{|1ZI!gvvtvJ7D1!L@z2BGjA1(Ng zs{W(6;3sx&Au+)*DD3NI&tA_mPjYEuHa}?Fv%gLF>o)I!Isl*U-e&uU%{y`Z>sk>Z z)Bzw3`R>u*r(t>q!RH{wLsS!WRexKC{<=1i*=PS!GHw8KnDZ_CdX-b(rU4cH!0W<&!yL> z((_dgc0E)x2nlNRIF%$qnUW_$ZPE@IVC?FbzGr9kcu9#77IXWX4{7h-8@#y+`6Oj=& z%A+hftIF_s<$Ckrb++EL-psklwA{#8@G~fBB0|@e@7rd)`EWQ4E zU8;|{H)y)=ufKj`=EU@g1z+`?Bkx;*bAHXOjJokazMand&1;IyZEx>+Z=3o=KQ?f+ zRDCQUfCG${s_DMjHP?@m2aMIj1o|>$Kx*r6Y}!c37wD@>KXzdS5p< zaF&9}6myL^i2Y@>6HO^0<5C#rxH9x>wD&Io7uK}LLHQ4O!@;|kKPRUw(Abs1F|BS+ z8^j%o$#Hr z@3k9X6BFZ}f5Tn>hFiUNLU&FU{5w_u&b)u;gJ6V4`d)D5UF->6H4nEUMDpd`U5xYZ zbPV(l3=DKuDNG3S1FG;!3T7x^;u!XfNk`e$_vr<@D$vzk3SOsRmI9i}SYB*#7yyp8 zy9f$fCfG2lt(9`ZKch5Gj=<=euPT;?WlUGtLJ^`@%h}fd7kcq21%%oZT5k&VFoa%Q zXfyaLb>hv`NZVg1u zx6sD~tJwnoN4T&WXqWNHBbF!FWi#%mG$@os^Ukb!S`6;4j|E zaSxevDCa0xhoIyfBy4SknZtIS}vi+q~bLrsQtNQl7-*?w{BrhG| z6N1YAyn*ksOr>K_qrl^2TFdub4$<<_4}#Ym7vL#*X&@6`n0biF^I#27Dg6L({!Nme zr+1qTI?4pd@>2m@{E+XvMv3XRua&yO4}(%~CQwZFKMvU`yKcKHu@Ph?a2=?V{W;;4 zonNQ)%Bio^gT*t*AiZDc7hYw&w|&+r4e1QZmOYa;*$;8(cF3c|<;9+GXz#imu%@1* zo)%|XzD|iC>|B$!na7wROjUdjhLvf7+qof1J6E%jEgO8CL0yOy1hoWo_{?7*Rtk8X zY?i|%PP-7OVpm| z`AlX!-LrAyIoQEZoF#$qMpP+%abhg4Y_!B(MSCB|5*CNNw0uqab*8h18lTxsu)T}$ zOTcP@q}0dUqYhL;nogT*@~y6V;d7Ey-{jVp>siW`*96k$-9%-5E#O^r$!0~pC$uEG z?%k*xw?JVd0D49%kX7I-mijzFS*oY5y@!&EPcDqNrkmGIFEF=KJYFjL?7+e9onKJK z=9pO*eUiB}P6IG&_Vrv}ZW$lFsm7o)3rW(e8_gqF&%J)qz#&1h1Cws~=0ZEhHf-tD zU^;~U&m}UN_}mj4rcI}~%zi7nJ~}Wm&O9@7>zF7-A?r*d67LY2+Ax9vYC4dLwvUf! z{z73pVQEJ@4H8+>ptfVNlJhFaoz&$4ppj1iUX+Ij4rUz_nc?o8q|(qk74OL>k!&Z$UHA)VA#>`BZHp6PJ z#(6EGCx1X#i#DW!_1Wfg)E3>f(*gd+ZO=Roc%9P&s4Unn&o{T+-0{}#AMT!CtGh_Y z*3Vy_y#4$?{??y->%C)z?!#*LVZI-fq?P2GWzRymxd?|V9_$8%w~7F54#mDuZF6XK z?exU-#9|l)fu&z;65M|Br{W9D?09|mjoomR=WA0*?70lV_$wjmokALV&sZ$BWwPUQu_GJAs{`~YA!f z9Imi9s2kZfU<(BnO2c&t^z>Ax!L#@-5Kzx5boIZY$xMrekznpd0F&tcE zfJ7|o7U`=9%hSi8{jmqbQU@9-c90~dGNxLxr%E9h%UDxn=YXHF_xHCgF$eE7=A^L*9dD>_}==sdgU zS++s2oiDI<-5xI;eVV(d0**h+O!CIDq_kb}SR1enX6C-Jl7p?Q>@J>9T<*pyi_&5p z8K&=;!6;MPdd{KjkaBfAlRAfedgp2HY#vt#|0&D52T&_rcD zW?ad6YT)FN{zD}PmVQDh`OSGLB#h(Vt?`!EF7`q*vDiU+`3eP76hLDGRRslZ1ZkSr zL{;KotB1B3CIM(O*;?xg(jNb3T0r}e5)_2Z1r4TO`#j9_QHc5>Rk8T$y&tMqL#vC` z&ye+cb?wJ4voBgu2NK+|*}13Q#i}|uISkh`LSxOX+B^0_c$*sDmiKQ%#u0peVo`{A zLgnCor19qQ`Py5KTj@e%s~XvQFY@@^$m4~`6Kdp%={}GLbFRC=wtTP+6|IRDBOQ6u z`Pu#Yc2u?op5XN0ep8#;)KzSFuGr8FXBVh!a~-Vgo9iIHZHc0?wNX^ICQ2krmC&$a z)=z&ALT&R7Y=aDKErhnJp{>)s9;obsx!Mpt)GzH0!0m1-NnSL_3g4dI$Rc zRiZE2JMF)$+b0PhNKf{**#Ful?RVM!+9}ett9^f`11eRz-n0(khfOww{TSWlq;sV9 z=9XkzX^89Sww?m!{$dS1qu}4uDAL53GXCJlgJf?Mz)MMJ>cFBTItCyIGlkBm0|T%$ z;6+fzLx51mVPJ>9hc{NUrg=PBddL<2>d7WV_liq49;7N9wc)dACaxY3#ZlgaWL^FE zltu_JlFW;=1CY@H(#SFCd;x}1hNQvv%Ck91saxKG9+@sdnQVc*a1-QwWPCViS|+|d z{iyu$p|$1Wlj6lJ<(I`>XhjmcvS42-r5ke2N9O2RHb>fU4KGjGZ=R z=kLtg*+hLXcAkg}P7Gil9iSZ9owMvT5(QFqd;^CA&NwKKb@aR|ilRDE)_5EqK_ClA z!sm!?xnGhfiqeG%!P&Qi*%)J34X})Y+Zmv3?~39f@@m)lNV08?WqX#y2Z>V#gc=Q_ zC$^@g9H|2Bya$+tJb=E@4YBNsle+s5)*}-ZoDqZ3iHcDv*)}MEGwG zf8Z4n4&jk;Xf!D&@Jen4k9Au?WLMi}9vjLs=NUQwPnMGNZ0ksT zXb2xZC9xP2r9rU6gxR$3M$3X67hpj#mg}ig*eyYXuKpU-`noe`diWlPCur>^v9BX3 zgBj?IMf>8|$;0x)3}+eWlLcE(s7#&4=X!3c>>0*t@bzp_a${0)DRUMVZ;}%U`)dw@ z;PXaDnJ+3$ZD5i@IcSHKjx001HyqP;xSDVb+sVaIPOAJM5PH|vZ(%nG>@%kf>v8d> zUHkk=a8k6vJp;bqXvY^EQE-_=#s^QTp=e}ikODX%AmSf;nDIs3@^UN%mv=k$KC3VTaH3?Os$ShJMK5E_ygD5uD65JfudezqweqZ;j$3iui}k+ zKX1wMez_P;QbqM7bGkJCb+zCV^pJuss>?CnaXN8gCQa;)Ua}!CDAwI+zH?t9p zrPn2nhX)3pK1Dl%|26V2Z>pqS^Mn&R(8}x*Nm^zXJ3 zq(}EaK5fAU%3cfxhWh}m5M#`<*ftJl-J=sSeU_TO44zD9lLtYarLmQhd$6UhhlqMO z$sQ0UVbP*&V;CuZzG}62vL!VeGTDHTNfgHzdr{BV{3IcH6t=M91ANe|cZme$u}QC4 zdSOkWG@I#v6YY;Gyo-N+Ky>Q8;h**oGY5Jo#h&xZHsefgh3Buhn^}&ungGd+CyCBdw|xso7{4hJA< zl=&)WlOHo%Tj@mQ=d=FUdC9@`4iR zM<`4A?-Ve>IGLS7&`Hh^$uB?iQL3yWC~$+~5R&fW+?wXDEQQK@Gww#B?afDL6p^^#QkBWx{vXNo1eLBtlxSms1f76qSOV)H7u6gPvJ@ z+7@)Q7OO(9kKGu%o|;L4rn5tr1ady$fCErHxbIt4@U2mO(A4-ntz`dMr~2Cp{*|hK zW!}HC7z$7KLgEmBhyO?Pmp2tJ`;(Hf*9=$h|F8iYCTz6SdrckK(?KL|T;i4A_Ve?8mA*E72ztv*e9 z%rory<-RnTIoA*}F%Fss=xg!e|B6|!e-CvMVi2>TN133821&BKL0W#`jl;Zsru@|a zym4CIILm3?aZif)9;wZ|Y1L%GZU8Mk1^vnuU$7(*j&j+OgCUNYHv!yo9+jWcP`;5V zyOtIz-)@HpKGR%IZMHjy{X4OHOAae=hlr`d5T$Z!5&>oUs|4*y-zs4~@?J$AuB3)b3L&2NA{)|7KHkFD%MeK5XdUT4ygbG&jyGYAS# zI-z#)jz-36CtawKbDr3rB?sJUx+*Q|FOa;D9hG%SRs&IQ(%-V(2X<<6S&)YO9M<-b z26Nste&y7ph^REe(a@hi-UH~umJ69?06=O~qb8WQEFo?A5Ne8Z%K?To3_Yaon+Z-f z2svTJ=}$N%1mAS!uPtdaxI zmDKDdbPE_@hT(}(rp@E-btzq%Tzy2-$q{@H3F(nN{N`e-6Jtf_6V9xBjS?ltA6j8$ z=l)uWTwQBwlBTF5B-yWAMu@LLg4oPDz5B*t|B&^0kC43$P&rhwfu~;>IQ&%qseyeb z2cCVJzK)R?!bU562FmF1^QqLu!9lP^p5D~h_$c{e0*~Y5T3Av>fHvuDf(#Fp<~uT7 zL=2!Glu4A%_HHSEfGfD-(F$hjJd-u}V}yp78AA)MN)o)DBo)#pGLMI(dMQanoGbs0 zo`skxHya2YvnsSi*r%vucuh}WpY$k9gm`6@7bwpFtXv4k^JnreV@Tk%_Cl8T zB30%z1yl6OrD@BV$Hh{$9uW-8AoYww(g{|Cc}rQ8qszZR1_}kVMAQEsF@Y^3@Xj-J zjQ$p#HqYiaSKVY^_rMlT-2HUxPj;~j7Tm9HR;%%uJ-lG|4{D=oZH)GF@q4JF9X<%- zYQj^!5a;0|QWsuN-bl_37OJ|{s_v;nMHdV%Y>pnoe50cfUayANvxoNsHM1SpUz&M| zL}op6@%#SjH|ytWeq8sXx<6=myJ3FEt%HS{t!mBIJEsc%$5sF1dH>^(0D5{@d=`96 zDL2?>HO-)-`iHG z->cT|g#)DpSAE{KYSHHQ>?-=3r=Oy~qQ5(DJ@GY^K9z zx~iw(e?s*?k!R;;pZc`za5Ypl9$^3M^Z{xkeY6o89uGN&gs@R%^2P9O7qz$UHA+Mk5)fnc#_HXI++CTJ4y;ZIcYea;~c|Bo3gRMvxkigGHDR$!yay^9Tn&t7&qVH3n}iSQryn9uCIfDHk!t zvgb~4SF8X{lm)&uLVf{2aL33I9T>w7Vu^|L;6{avKjpBJ@r9gM)KW2#f$5tl0I;Oc zgrTh=fM9ItchP*}f&taKvE7=gm~CY(JlwbM0AmB5dV1gpKn=`J*lY6H_4jCjP*Qw- zgD6)!>=odV8HVFpBn#bd&_e&a1P0SbET-As#*7=w6wy4E-qOR0p{!VrKIsUxiWyTo z^c*VHQyg32+Y(h~#gR4lB-<8zp1y{miIyq1at$vK9nX#%J~OL0?E~ZLfLPR4DHg4$ zFTNUo!%wkZdW$H4^3EOEId4!}dKvVaG4MMKVIAe~xsL}P-HMz&i@dBQTkp=qu}lijih zwRXu~*@s^Upp_Whwk%sFY7etuSXu=t^U1lFPa#(=iTQ}U<=~Q-kIJ*UGNy-GY*3Px zQ8v+ys3SP$rAMW~v^DqJHP(CVJ|+5ZT{#~pQ!D5{)TXxlzI-Kz@J)Km|MF)%MS+QC z!q+TcuFq^Nr>Xpky|p%#t76jg$g(4H?KL6isZ3E>AGvP%^&;0_6Ed4k_40giO{{Mx zz1PW{ycH%Z%fb{;%-#zIeVlXtpkkH5cSai%2{mLNV-S@nN7J_ybVv;rAJP?$Cm=lLgE?yOAImW<0A-Na%te1=o#Z6c(s+d&z-n1*7(vnzR9mkMi)C=UVd)5M^B_IJYHf!xYRp2PW(G~b=C?VTOC`NHfA z`0Vtz_+xX(`ylggpRia4zRT>ed?rcG1G$Gu@ z&v|jScW&hyhl~f>G>=9t6{UH}=1dG1#*C?c5fhj`aZMG5lnC59LfbnIZGP0qaMjW& zmBjC4Z9Th6;$*)rePs)q21S`hpv@DFDPr^F%NKHlTC)w+(bjRpp?t%kUku!O=8ibm zHW$Z#+x%t<=i2b1;^cFrNhu;dcOK%JP(W11$6;Lo26m8$=5*QcSoyyw;uV@j_Bhr_dr=f5C*jDD#do42PX^$8!|1^PhHv^LCsWpW5K;iWqz~x7cbk^=j(dk9C{;hGclXEQ}D zSnT_&XHI}EBS!{r4$sMNkLFvq{&MISiQ9=gzgJjsuuykMtvgikA6ET`;eR>kowk$l z8Z1sk&r|S#5PbdUjid7~1HNM52v9XVH#~1%n6LeL^B*_ki(V_Ys4KVd4|z>{3hr&H zdt08Jkhi1XL`R?;AT@l5@Rl)6=^J1=#^$msQ}H?Hz^ z_^TJ*yHwbIP~CnI_l1T-D#G9)HF#+1FyDdUfCNHxte>{C*)+RncIVAK^S$}-IT?fu*#${F-+k2?jy5a3QW22)jIE2`f43Z{Y9Uy^J)r!CA-05Ua-c`(;6k# zcnJT-fu+jT0Ys2lw+YWcd+Z5&TXB50b!9StkAO*iq!Rz|f7sdR65%ZtY)ejNCG=Yf+ zYpGr=6N-dhV%M{D?c@OU+Z2PKD&H+%et(?4jLkpaIyk5R?g`3%3OXtH76nXN`4(Mm zr(hgG$%zdHAV^Ch$UXLr0eIU_E9ewZh~%4@zA?rS0NMZOKHPl6hC;<3e{YN0Z6c~8n>Au0OWHOFDdAxktosCzo8&PxBr5!R^h7T zF}A-jlVoPi$V`BgcM+%Lg6R_Co}QE1Cs&jrCh#r}%I+Pw8#8o4NJ&s)!;ur6;s z7ldfudKQIMdF#2fVheWZ8o3q}n~MxX0ZAF>qEi%i)4R%G_F1)d4P?UNZpei7x9%+> z^rS{`L97?Cr_czt9TDlhDg1`5Nraa~Bj~9Ww=D|RU{ioHF@mTNYMrgU*;0gP{Y25z z4n1!%fQ<>&#X!wsz!kE6EFk!Vf~l&-$Uaeo;p+0?$L#qh=C_A!LZo|kJJ8*&)9*|9 za9<(Zr-u75#EZ^4aUJ|b=)sm25ubor8sH0U-}#uHe^P$A+bM!}um(*6zUG#g87(?I z(>w6_aDRlpX4DLdrYgkRRJ&O3527^)KA~XBx7b=m`B;N?p=QObw)5H?j zV=rb65+lG~%o^KNV6i$viLJpFArhV4esdR9Vi!n}q9;6EJJU3`4W3dxn+l#ys%KNt z^BlUC<=Tc0j!*|jsDmRm>XyimO@v#F<-^&AkJ+0~%vF95xy&8;zCC29<`bit;W>KGT4_C+9uA1y8T)=`9A> zD0`k<^f@Udf=?)b8beRngcX6Ux!yI4u196w`sGpJskFN2>B4s?s2Bv;A%kMPMltYi ziU>`4PgB9uqIz0j)Zy7uT+#OS^KTE5a%Br(haULclnH`QC|C>`nXuJs$;9Sax!|vw zIW+SWX~0&3?$!gJhcZEcAwnh*!4_Jy?If^*0AC`sg;cTT<61q!$6>v^k9~UeKMv?U zZMq8TeQ0`y+>VGCILh`}Tnx~~ZjAln1(Axp1ogjP6+-uf#=An}+{(F^3c?0e*pL@C zfCkql&E@>619`EpAoi(ZUs1%Mbct|VqX(2_&9yfAIfx?q7A1P~EqL|jbM8uh_5Qrr zTM&CyvDY+%BzMtMi?!O4uRC1u98o<-us4f(zhg15q>I>Wnoi*xZd*>~#Zv|Glq#NL zb%}`}yY;|SmjTq}l&Kq0y#sjEyVyjL&x(SpX6i!GgVs2`(xSuTqCs)dptx*P_QeK~ nV74`I3zC02d)MBWw>N^zm^$#v!D|Pn*dLUez&Z9thP(eC9@IhPrjApms2^G&K>HB6DbNCaAPoZE4j@24k%#ta4Lg9Ur+)u` zW@cx2v7G`1I!m6NIdjf`&iT)O{`>x_rKM5A_24g4s&rVA{(~NzD=cp0FUz>OEvb?! z=cFn5ye!jwAQw0v;P2r1Ab*F>hxj{uKFr^d^HF>UbFrz0^9`~Tkd8}g=q*VNe;AOY zkMS?A^Nsu_f;UmE>BAu2;opAOtOiD;c3qImrp;_2Zw%qNB|B9t=w{L| z^=y73WB1}O8;1O40*|*PO*${D5@sx8wry&=+VEBw^KDZ%sx7z+s~u|VTcPt29C2j-r1MJJsZ+)a`gB@X6|BhzHrpK~l>5GM;mLDmU^o(}#ST1c`?t4ue>l-K*`$kJah7ZX>s{FRHRvSSyG ztf}=C)0xZZ3C*}TPR$RA)hCKGG>2?HYbKM|x>sN^;k;?ZER4-4u1nSK?Um4tmgmvVsiC2;pER0=x5H=G7`57x*n9ggu4?(mPM$jeP+?LAnbs%K~-}Ef5vUJHs z(iW#unhm1frN2MhRF)RpC$|x9%E1rO`(qaZ`UOWMeFI(rvk|dkoz^0-9n#zAzLSbB z6jngLVuWx5ge!VG)kKp?B8lX+&8tzvFFMf5cm@S9)3l-TOtoWk<>hKi+l}+{q4!&s zTlQB1)uz_vrX7n-@oM{~&)fHY*1mV)$Wr@(<@N)WBh}XSN`p>7tnig|uH+{v7h^qW z0E`9J!_~8RPediw8qmA(%nOYNJ!{;CT8E(A$#=a z?nVCNnTtUqf@otjGSRY5j7o2!q8UXzBJjM4DhQy?cl@62eD7&g&wK74<@H#N$>dZ) zE#+`ztmb6$%~Coi4iIgXTFBreZKU2?sn~(y*OHhdZKob_3Ib`QP+WIE)zIO^(BWDr z5Pqm8tx?1x;f*zEjiOBsAFN616k>21H-mro3W+=U%Nw})i?HK9c=5p&>6ZF^r<52>ARMbF33>JhaIts2xv)h*zRjSUjoA66ezccQil z_XpL-)xEfH#{CoOlWH&SThyo2I9hM0NLS_at>E3?u_A)h)BlcHzgEyM8;W){oiTGW zN-ld@Q__l>&6o~wm@AhtT5&E=G=sf_D|DSFV1MmkFcT``JU226?j zLK>v?tY#z>Wpq;00TTb_bO9WBYO0V|ieTBAo@a=~La~%fn|ME|F)VS46OH^Zm_@a& z%oIvW2CSZkud{YBjkL|^c|QI9q9e^JT`VSSXf)qsafW8xdjQaMyFN2MaUd>w4C_id zN7I5dyP^RZ&Y-F`p3U?8?14%;3p}MzWVxqg^X}vY>EbbMV#2wcq4ZB_=45}0Cjj=T zWy}9pFCj7sDU(1kFFUPx0U48pQchLIG$mI^tC|Y5o-maxgkR1mD8+(dWJ!RL z)YHWF*kDSAn6?24TESd|@NEE69 zv3|vYsTWwDVnqW)@5MAw%kXlAX&aP4m`w~`k|ebRJ41?5TAxwuc1$8PGV~`gI>Ym+ zF0>X@tRg@$Z9#SlZ!WK#L4ulc8sS;&9c?VmK`xtNnzfJB8NDzDrDuld7KDNA&E`S+ znqd-JaoA~C!lIwz4I(-|`sqB+7Wzk4FXVY!ui(hDB2_E^7{LLI^fw+#fI!dQ1LuZc zIXiIX%&8Mc2S!f}4<$ziM@LT#9UpOyCrH4Y#PGarHZkVXrF>?Rhw?9z&+cUU3Lgr{ zIqtgtjBTVd66w@Wr$MHu#3q9XhV#m)Y`%0AXH`{(N0iqYkaM=QtEBKM29#h%yZ2z& z@77z|a|aI5p+966Y-Q~b&ESB|j`BFBd9^TY&@_}3R*}Lk8K#z2?Op6IruFocq8AEg zk^uEPJVcqE%w{GT^@6%}bW(H;d={*YcM$7(ZBnZ$IX@VBT0w*dz!gbp?@#@JRn-LRw+VM0sRU!#ULL4FUCNn8Kk-Vza=l_^ zMk$Qb386Oj+2YZY6ZNqMVid`l<|F7-oX2+txL@pcOVsU`j%_=>eFyt-R8`z7K`fkW6Nv*&E5E zqr+ZjC6D`DvkfFyqkkD)jDsldUzhI2THcP{h<+aH{w&r#-#x!`;p|eZcRAL(80)QW z*#mWdLj@mJWsX@b&Pis=#flgp%DicX#tMa;4@YE=LW7mRT)+)5gwna{TK+nkyzIve zY4XPAazKYYI3k&@1_Z4aI`Pi~YVd;az+*3k8h29fR|2H=3 z6qp*$grBcDJWcr~e#VqV6uk-naOB7f9F?)O0fw6cgJs#7Rv^N4GXsr^MQ=Wv(R3FU zb{%|vN;3?y-h{LuPM0IC1H_#vsG66n@c3)1HU%SLFX6)a4D}6Ls1h9ejQMuFUm=B? zMy7MS7E0Wy+ua3)^efD13rZ?Qnm`KdYMdD{vs2MV8Bb?(B}hGziBnlLdE1=qbVVL*(z|#zwZBM6xFxHL~qm;=2nd2qkzux`WwJoFTEJwL^h4>o@Vp;*Q zc|ZdgC>-oUaCD*!>tWQ+ql=B$;swmd7JvkRlm=3iSr`gQ=!ZqKj?4N(pxJoX3KR@0 zYNOf;!tk`3&z2xXr?f$$4y(zdz&f0P4mbDL$&z+>f^FA|4uFVRUE6q+myuu~qHdVF z6i{53{@5*TfI0i__ul#5{OP5ZgUc-kVbiv@*Q8j(hHC33m_98#s++gZmF{lbSqlW) zyFWTzlkin9z6gdpHhd+as7c|L4Yg*et@HENU7xk?S_pjfWnicR3`9}BJP|G2Yy90(^ zfQe zDu>8baN|N*nvG!AWS6eG)D^6BPX3-W8=Z}nqgZXnY(u%B909y=Rw_rz4Fr$AJtIbL zbYiSXImTn%R71>OBS0syR~(?3HQ5I2J+h0SDnVglMwm)5AtX~Np`Ft?SM@@%=;(BU zE(CwJxe+P9Hj{K*d{mWCUM2TRT?HZCx(IPeYW<{MC{0X)YZJK<>~ScLWW4dogfTi* zWQ7k$lstpP_@-R81VwO)Odqyz$Fmv5oGF4&V=Z~Ch5Vf0Qf}*)9gD)|M$ppxX|(>7 z0TH07Wc{g{?&(2n$x&cd&5tZ)Oiq}}X&suNZ9jlR0nhHRsLiU%$&uk9p5DVy6*IXK zua%S?YOF${7^ZiwBV@DFir_w+f^wf%@-P8_Fwuo9ZZJCHiO~5Bjnqw{*xRN$Z5LZm zyqRjDL}q9ykL4K|U<{U8DwV|M#uLhkam+wi8B>~?C4(P5-RY|Z&Bz}x;fTN#F?pg7 zn6en1JeTk*WUmSH3_u7UGdx8P5^YH&=%rs_Is~U9ro5W$*pLuS>vTtpvDb*9ctsej zz8YQ(t;Lt>_i?LKu3|N-zFLiF_nf1fpZ|Hm>~CzyBwN`Lx%ui zQ|%?AkWcUup_aRC6A1+e#UMuy8P5Iv%HhPL?psSv4q1U@ax@;bf>0izLo)5_|5^GSCe)%?BSwvwA#^i`}y~tU)aCY5nt|z zlK|aPZR`F+XVhYmHJz*W9JK%X62PH}0t%z1P|?|5)XRl^@>QzI!e-H*&K9W7Hzj=53YZ z)onX}@$}E0UKsu93-7=1_NmG%b1&WN-a*2-my5a3y^hWE(~BMZ@mKBHKX-iorJJYk zZQZ@l^M2o4bS?^*mE&_Sy?wfJ8sk(yar4ck(>j*Cjh11{-087=|?=mxD=H_%%o-1qJM@ zEUSUv1pSbokY+Wo^D` zukYr52~wB$v2-U80x>U%pxw3%*(k zlJGSiyaE^cIm~W0{DZI>89@XPBe-~hiWU1HSPm!MnjhJ1r)5_`krs$lR$VJ&H^4yy z)P~0ND7N^Oq6IG!!vZ10xM|Af=Y>*sTT+eu8`nJI}=P584R*K7}(!=QZM=`o{_ zLy(hA8)1yWIbDBpJvqX0<<8v)gdWHP!cL)8LhJvt$>y$SwUl`z@s#@(>r07cq_9SK z!Zf%r>kH)=86tjTFf&5fZOsa4SGCO0u?Kr!$+M#p*dxKV!pLK4>3tx_N8=qVut=al zN`)@Luc`Ndu&pp_fL7yarlC=&gA`+>jtE+XC~&Kj`vvl;FjYjY6(R>5wIRg{ZKA^? z!mbNLl;;apWN>JBaA*|YCq`a6an_3Bd6aHq5Y#N~Z3|F%;}A>Zz~*rb!WN(}@>_x;9`Y;H8?UmU`{PatBI>Ez&%XEULg<$pK8Y=LJiXlU zbR~ATxqZ2L`~2%m&HI;|_gCcVrX3aeMq@1yZP<9Xebe0J!sufA!KLu#=Ku^07xO48(M7lTKiIL+j4B% zVr*NL1?Lgq_fDYw$R6oV$5ThTf}b`vk_QsY;fpg7a3{W?Re}@OZx3VmoV6o2SmpOW?=}J+Uc`N0p z?DfR0d<$bSJ{u?p);5j(K2p8IbY&rpQx5p&0mC)G#^gcr|HT98IZSH}slal86xsD$@AiGOPfG{^x zSG0$Dg^*@2KuZQ7!KY{o5j(I&K_d1GQ@nKz>E%v{m3Uyq4*S%DU~U49;Rr4P`VfOn zC5dyRaPKyhe_OISD=PeB35t zMs@TIUQJWHi{>rn+y~by5Gi<}?YH|T=c!nXhzon78VTDNqI@Bw9w89L+|(|Z5-F1G z>EVQO{T+SX(ApQ1w#WAO@Hl9P5cVW`1%;>}XkkvewCKdagja*@Ll32*PaVsQIkpEU zq5Y&%FCz4dfP*;$KW&`=*!0e88hqrCj$`!$M3E;%#mI1{NHoWS$26Lm<72VyTncv= zoCp=+>Kp=Ub_AO?SI_~b<|tJ(5Q|}&xqVuE+eeuQE)L;=po9Q_0~>pGzJVWzGd6ev zjp8|=e2~55D&!&10izjN4}8{a#WPnB@l!$UP~wDo>Q2kfz4B4IQ#X~Jm}HMJ<1m*4 z0*x8CS*CDcRL!GPj%XTrxySocVtIXtn)hLw;4>n3IjN6za_9YAi`v~emB_ii7Dw<5 zX{)iILJqIlsR)kBDTvbrI24aqjafh?Qa}WQQ-R2bY6Zc#tY{V?ERd8Hh5wpJ%9ooo zfOfvzB>fH4_!SZ{-tVa;ncr|tzbH%1U2~Za9$RYKwcNA|LcU?&-Hp2zf=e5FmN)iP zj^2eyY~1|Lt?$5SZb)ze`@41HyWfB3`)|+Qm?gC!ad-RPg`*#JEN$;w-rgrn<@>Oz z?e^@F9<@S59uIoF&Sx`mV)%maJ+l+~G)^yY`UV^g+Ep{-k(?4~TWs-`*&Y2S#lpVU z;)U(%v3VgmLlh&+!-n-sP*||xHJ!>4HAo+SYuJ?Q*_tO;xuBn$jh2J@zH;=EYf+n& zUu9qQd?jBkQ3qe+0o$q!&PIO_C1&&?`)3*E;5|V2mrwVP}iiH-2e1`=QoQh*nsFq>Gs%p;*uaock*D z3K9jvG3%A3gfn|9N%IhNBgnv2P{o_i z%X<3Z9@V6Aj%AVJH$zGnB$ycVe;uNA``7LL4Ddf;`;{Ma-_tlmGpQ6!!+Rc)vV#pG zSF}gC)xp)B)Q`BpELqo2fI$r%(@)_`KaC>ZBwW-(R546N4;3R+yhg?ARGg#YJQWvF zSk1KONt+(xF^_3ZLQF(xv(!)?7b&tSJQ&0t9lQzebOXa7y1CYN)Dy6!n*X9MZNf-@ zNnXcFuZ3ccIc_d0Pb>r%f}eCQwLiJs{v?UPoxj~(?b4+U_R3baogF4S+bPzvvlsUbEN-PgpN)O*Yi#T$fTKY-a8OzKtW{a) zSZdw3+`4Zuw$FGGnE6%bz%J<@ng=?9ccRU>z0(mI*c`pHIY{?gWxC(S_q!U8><`|F z?>@3S_-R`^mAk{Jv7+|wJ=kt0?2|~5XD9IN{x;w;eqJzPaOSel`i8)fVBgAL{tIqy zOIgZjmyyRFT)^|{Yo#TPyrA`32K@4kTY?N$Umv3CW49W%`Ob^5`e#G%6NlE$!SVOd z!=CW*F8kH!)KlJ5l_?AC;5@YqxE>x&?u$&eL z%2AfXn`<536KHqZ3dGwv6SYohe{UsLZQ8ilw6ogW`R?#L!}G_NntPU;dls8}sC_r!dkA!V7Cs;7Y1SGQ>9Mjosz&*ZG)K*_X@^%_A)W`es1yEJqhG*VUJQW@w8< zhjNs?MH=N`-85bM9zSTJiytEz?-pC6;swV9Kk*d8f zsnr8O5#n^KT%mB8f0(cmo!@sih(ObIfV8Xw{ftL{V4vTTzDRFZ;%tqk2&$Esf-j!*Y5{K*j*GHW$>yYR;5prIG>w5l8(~^ z;BBuTL4~L)Ww1Bi+zwlfb2kO{{fY^=uiPQ+J}!5mKFH98_bHFP61g9COwDoQ(SdMx z)CI)5;VV3Q?fp4}ojmV$bd*mYQ~N)i2Kl5!u8jC`Lmeybq`pb|AR&+Jef>Eqoei{6)X;$RJQQ!gR2iteS?%cLpiaY5$HCFiOfripcyn{kuj+gE-Y>R(3MMC%Lq`!S7Bh)h9#(SpkB%r&fP^jRa{XK>|gks^;5EwW{Zz#0M?nFILcR4D4Kn3lo z)nez(XYk`F-uXCcdFNjg`SW|JDHSx9@dCE|{&j4)_|yXNaIA(L-B|5aIS}3pwe9PQ zSXcP5nzTl7SlZE33qBw2tezbDw}X6Flkm7^@nT>by;-B^?+L@p=`TiQse4Ct)0SFO zBD}vQtx=50(o@gWg6#x!jiOf?lF!PuV4QvcxkmA-EQepD0PVLd1@RL`<1O@q&hZj{ zQcb^s21BrI=s%}BP6s=KJ1c^d3YEZ;O=|-<=jCf!X(CZFvpGW#QA^?``dd`+X6>ds zO3~pBd=Pt91b?2_Z=eqQCmH{W0tT)uSEW6R{=a)t^L74IrKaorsY(sk`BSaG+PEm$ sfA^%`MgLzd(k6q6t}ecyy07Xl_FoIhgt+y;Dx+VBw_kltBVOwN0B`^dd;kCd literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask/__pycache__/ctx.cpython-311.pyc b/.venv/Lib/site-packages/flask/__pycache__/ctx.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..481750a8cd156c946d9d5077d49c2759377f2fdf GIT binary patch literal 20638 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 HjNbnMRs&SH literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask/__pycache__/helpers.cpython-311.pyc b/.venv/Lib/site-packages/flask/__pycache__/helpers.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..58f98879869561554ff7cceea25493301910db0e GIT binary patch literal 29796 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask/__pycache__/sessions.cpython-311.pyc b/.venv/Lib/site-packages/flask/__pycache__/sessions.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f4cdaba6a7f10fb27270518bac1aec07cb5b3dad GIT binary patch literal 17351 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 MS<%BCDliuKKUs@zJ^%m! literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask/__pycache__/signals.cpython-311.pyc b/.venv/Lib/site-packages/flask/__pycache__/signals.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b94e9a7539d23ad56d2f722e1b2f32f777052587 GIT binary patch literal 1979 zcmZ`(&2Jk;6rc6S+HvAK{z#n!NESmCjATcGPy&UdX#@0t(nEqOS(cWucakh#?=G|B zq_L11Ar3|ADHo$$f`k-=!XL9nK3F3mMM6FFQW=F)PP|=vE!(Zfvv1$L{mpwb@4cUY zk47U1#`SOCD)j(D|2PY8_`8a5^-@5nffS?&8mbBfL2z`R<}3K!cc2h}w_giZ#eygx zA0py8Y`yUOphAd*ehv4R1Bwzj2j3U)bVp%gEHXHPjEqH!Bgo0I$j}IKYAiB5f{czu zPK+RLj73I9kg>7I$r0rASme|QGCmd=9YH3Pq>}h4P)I7iZIn&Da0-$Y_$1bKgJGr` zy0r!Ci7i|umWj)x9%rO#YM7B6CAvZ=QR+8KWY?gcA?E?=F-pF#5sT$4hA9K!v}f2= zb=BGjOUkn_f~l(Sv+gy zm?p%E!4)jLM{>Iwb}&4k!>zdAVw8)Nuo~5`gDk(HAC>#93F!#J1EdhH_CaZ&AAk@Q zAE<~fumRk6eO>V}AeA>1|DS<#*niO@7I;ERa2v6Zhd|(SxGX;kS#gWUEp<=FnkC}{ ztZKNVk-D+7Po$++>`M}6jH;y?Ba&)K3Na}uLx~g#>xy)!YMN9c5+zmR0Bou*eF+(; zNFU@^^3rxUh=eJTuy%-#EU6za|H8Q_)IS0hELSvgK(w7~fQJt;)uCDz4>%f6Z1y5T zl^%6J@f#c7k-nhRpjm-BiL{(7N!Nw@pBBHd2(^k2a7iuUqG1w!+o;hpDY|FNJtC#t zhH2(@YRsT2){6N9q8}8$R!c=oh311^tUxWTqEpPuaxW!$^N3H%@*aWSWmJ}F0>Y)8 zxL<)dM(xm~9n1U`%GjaI-{I+J(T-1uu0EeyXs2g86TykdzX-&Cj_9~z3Qeb;vgeW6 zUsBD;LMyUh2Ntft70L$O`%n>d>Xec?e|6aukI3?F4SI<{bf@H8WJf0CiVKWJopq?B zsd|M_>NE)t%e|v>v8(Vt!DNqMyhpH}LG}p7J%Y(Sf^m;vvPUrP5ezoDgpnPBafe{w z%_W%JCm0_f*f4&8O>&oDe8}VyjC%x=djxZ{{|BN;xG0T-xDJ0-HI$l0*61x*I=x`s z0@?8kg3v}8dw5==gze2XiXFSZOZ1jKJUb$qntA%k&v%~PISyZ@-fTQPd1$};aWl2r zO0C)`-ky8=Z1Hr_&Tcg4?zQIb+303FG2d7|S++ADHWMqY#L983oqVIQezI=A^HDQ- zyOq3cqv>{fvGL^OiM{lBGriVIuh}Too|VpGr!o7z_2%r|*6dvy&9vt;XUnI{_WSpn e^P8>tO&g`#uQ|hOOs|}wBSwV94jLoeH2x0&s0@4n literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask/__pycache__/templating.cpython-311.pyc b/.venv/Lib/site-packages/flask/__pycache__/templating.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..74c63ca7db92d1b3f02e4486df86a2bb63193bce GIT binary patch literal 10610 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 bpB|m0t(p2dNq-}?bCUhep`0T#Tj_rQCQrCf literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask/__pycache__/testing.cpython-311.pyc b/.venv/Lib/site-packages/flask/__pycache__/testing.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eca0895b46cddc67d4f95d8a212da17bc9eb14b5 GIT binary patch literal 14159 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 H*oyuSUfz~j literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask/__pycache__/typing.cpython-311.pyc b/.venv/Lib/site-packages/flask/__pycache__/typing.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e85c2cfb8ad8f8128f29d7daf1c4c2a9460459a6 GIT binary patch literal 3447 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask/__pycache__/wrappers.cpython-311.pyc b/.venv/Lib/site-packages/flask/__pycache__/wrappers.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..46501bd0d503d140b036d2ba462d5ced73d2c394 GIT binary patch literal 6766 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 UEJN{Ii^ch`i28M#E+Mo30M%~;5C8xG literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask/app.py b/.venv/Lib/site-packages/flask/app.py new file mode 100644 index 000000000..3b6b38d8a --- /dev/null +++ b/.venv/Lib/site-packages/flask/app.py @@ -0,0 +1,2213 @@ +from __future__ import annotations + +import logging +import os +import sys +import typing as t +import weakref +from collections.abc import Iterator as _abc_Iterator +from datetime import timedelta +from inspect import iscoroutinefunction +from itertools import chain +from types import TracebackType +from urllib.parse import quote as _url_quote + +import click +from werkzeug.datastructures import Headers +from werkzeug.datastructures import ImmutableDict +from werkzeug.exceptions import Aborter +from werkzeug.exceptions import BadRequest +from werkzeug.exceptions import BadRequestKeyError +from werkzeug.exceptions import HTTPException +from werkzeug.exceptions import InternalServerError +from werkzeug.routing import BuildError +from werkzeug.routing import Map +from werkzeug.routing import MapAdapter +from werkzeug.routing import RequestRedirect +from werkzeug.routing import RoutingException +from werkzeug.routing import Rule +from werkzeug.serving import is_running_from_reloader +from werkzeug.utils import cached_property +from werkzeug.utils import redirect as _wz_redirect +from werkzeug.wrappers import Response as BaseResponse + +from . import cli +from . import typing as ft +from .config import Config +from .config import ConfigAttribute +from .ctx import _AppCtxGlobals +from .ctx import AppContext +from .ctx import RequestContext +from .globals import _cv_app +from .globals import _cv_request +from .globals import g +from .globals import request +from .globals import request_ctx +from .globals import session +from .helpers import _split_blueprint_path +from .helpers import get_debug_flag +from .helpers import get_flashed_messages +from .helpers import get_load_dotenv +from .json.provider import DefaultJSONProvider +from .json.provider import JSONProvider +from .logging import create_logger +from .scaffold import _endpoint_from_view_func +from .scaffold import _sentinel +from .scaffold import find_package +from .scaffold import Scaffold +from .scaffold import setupmethod +from .sessions import SecureCookieSessionInterface +from .sessions import SessionInterface +from .signals import appcontext_tearing_down +from .signals import got_request_exception +from .signals import request_finished +from .signals import request_started +from .signals import request_tearing_down +from .templating import DispatchingJinjaLoader +from .templating import Environment +from .wrappers import Request +from .wrappers import Response + +if t.TYPE_CHECKING: # pragma: no cover + from .blueprints import Blueprint + from .testing import FlaskClient + from .testing import FlaskCliRunner + +T_shell_context_processor = t.TypeVar( + "T_shell_context_processor", bound=ft.ShellContextProcessorCallable +) +T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) +T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) +T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) +T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) + + +def _make_timedelta(value: timedelta | int | None) -> timedelta | None: + if value is None or isinstance(value, timedelta): + return value + + return timedelta(seconds=value) + + +class Flask(Scaffold): + """The flask object implements a WSGI application and acts as the central + object. It is passed the name of the module or package of the + application. Once it is created it will act as a central registry for + the view functions, the URL rules, template configuration and much more. + + The name of the package is used to resolve resources from inside the + package or the folder the module is contained in depending on if the + package parameter resolves to an actual python package (a folder with + an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file). + + For more information about resource loading, see :func:`open_resource`. + + Usually you create a :class:`Flask` instance in your main module or + in the :file:`__init__.py` file of your package like this:: + + from flask import Flask + app = Flask(__name__) + + .. admonition:: About the First Parameter + + The idea of the first parameter is to give Flask an idea of what + belongs to your application. This name is used to find resources + on the filesystem, can be used by extensions to improve debugging + information and a lot more. + + So it's important what you provide there. If you are using a single + module, `__name__` is always the correct value. If you however are + using a package, it's usually recommended to hardcode the name of + your package there. + + For example if your application is defined in :file:`yourapplication/app.py` + you should create it with one of the two versions below:: + + app = Flask('yourapplication') + app = Flask(__name__.split('.')[0]) + + Why is that? The application will work even with `__name__`, thanks + to how resources are looked up. However it will make debugging more + painful. Certain extensions can make assumptions based on the + import name of your application. For example the Flask-SQLAlchemy + extension will look for the code in your application that triggered + an SQL query in debug mode. If the import name is not properly set + up, that debugging information is lost. (For example it would only + pick up SQL queries in `yourapplication.app` and not + `yourapplication.views.frontend`) + + .. versionadded:: 0.7 + The `static_url_path`, `static_folder`, and `template_folder` + parameters were added. + + .. versionadded:: 0.8 + The `instance_path` and `instance_relative_config` parameters were + added. + + .. versionadded:: 0.11 + The `root_path` parameter was added. + + .. versionadded:: 1.0 + The ``host_matching`` and ``static_host`` parameters were added. + + .. versionadded:: 1.0 + The ``subdomain_matching`` parameter was added. Subdomain + matching needs to be enabled manually now. Setting + :data:`SERVER_NAME` does not implicitly enable it. + + :param import_name: the name of the application package + :param static_url_path: can be used to specify a different path for the + static files on the web. Defaults to the name + of the `static_folder` folder. + :param static_folder: The folder with static files that is served at + ``static_url_path``. Relative to the application ``root_path`` + or an absolute path. Defaults to ``'static'``. + :param static_host: the host to use when adding the static route. + Defaults to None. Required when using ``host_matching=True`` + with a ``static_folder`` configured. + :param host_matching: set ``url_map.host_matching`` attribute. + Defaults to False. + :param subdomain_matching: consider the subdomain relative to + :data:`SERVER_NAME` when matching routes. Defaults to False. + :param template_folder: the folder that contains the templates that should + be used by the application. Defaults to + ``'templates'`` folder in the root path of the + application. + :param instance_path: An alternative instance path for the application. + By default the folder ``'instance'`` next to the + package or module is assumed to be the instance + path. + :param instance_relative_config: if set to ``True`` relative filenames + for loading the config are assumed to + be relative to the instance path instead + of the application root. + :param root_path: The path to the root of the application files. + This should only be set manually when it can't be detected + automatically, such as for namespace packages. + """ + + #: The class that is used for request objects. See :class:`~flask.Request` + #: for more information. + request_class = Request + + #: The class that is used for response objects. See + #: :class:`~flask.Response` for more information. + response_class = Response + + #: The class of the object assigned to :attr:`aborter`, created by + #: :meth:`create_aborter`. That object is called by + #: :func:`flask.abort` to raise HTTP errors, and can be + #: called directly as well. + #: + #: Defaults to :class:`werkzeug.exceptions.Aborter`. + #: + #: .. versionadded:: 2.2 + aborter_class = Aborter + + #: The class that is used for the Jinja environment. + #: + #: .. versionadded:: 0.11 + jinja_environment = Environment + + #: The class that is used for the :data:`~flask.g` instance. + #: + #: Example use cases for a custom class: + #: + #: 1. Store arbitrary attributes on flask.g. + #: 2. Add a property for lazy per-request database connectors. + #: 3. Return None instead of AttributeError on unexpected attributes. + #: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g. + #: + #: In Flask 0.9 this property was called `request_globals_class` but it + #: was changed in 0.10 to :attr:`app_ctx_globals_class` because the + #: flask.g object is now application context scoped. + #: + #: .. versionadded:: 0.10 + app_ctx_globals_class = _AppCtxGlobals + + #: The class that is used for the ``config`` attribute of this app. + #: Defaults to :class:`~flask.Config`. + #: + #: Example use cases for a custom class: + #: + #: 1. Default values for certain config options. + #: 2. Access to config values through attributes in addition to keys. + #: + #: .. versionadded:: 0.11 + config_class = Config + + #: The testing flag. Set this to ``True`` to enable the test mode of + #: Flask extensions (and in the future probably also Flask itself). + #: For example this might activate test helpers that have an + #: additional runtime cost which should not be enabled by default. + #: + #: If this is enabled and PROPAGATE_EXCEPTIONS is not changed from the + #: default it's implicitly enabled. + #: + #: This attribute can also be configured from the config with the + #: ``TESTING`` configuration key. Defaults to ``False``. + testing = ConfigAttribute("TESTING") + + #: If a secret key is set, cryptographic components can use this to + #: sign cookies and other things. Set this to a complex random value + #: when you want to use the secure cookie for instance. + #: + #: This attribute can also be configured from the config with the + #: :data:`SECRET_KEY` configuration key. Defaults to ``None``. + secret_key = ConfigAttribute("SECRET_KEY") + + #: 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 + ) + + json_provider_class: type[JSONProvider] = DefaultJSONProvider + """A subclass of :class:`~flask.json.provider.JSONProvider`. An + instance is created and assigned to :attr:`app.json` when creating + the app. + + The default, :class:`~flask.json.provider.DefaultJSONProvider`, uses + Python's built-in :mod:`json` library. A different provider can use + a different JSON library. + + .. versionadded:: 2.2 + """ + + #: Options that are passed to the Jinja environment in + #: :meth:`create_jinja_environment`. Changing these options after + #: the environment is created (accessing :attr:`jinja_env`) will + #: have no effect. + #: + #: .. versionchanged:: 1.1.0 + #: This is a ``dict`` instead of an ``ImmutableDict`` to allow + #: easier configuration. + #: + jinja_options: dict = {} + + #: Default configuration parameters. + default_config = ImmutableDict( + { + "DEBUG": None, + "TESTING": False, + "PROPAGATE_EXCEPTIONS": None, + "SECRET_KEY": None, + "PERMANENT_SESSION_LIFETIME": timedelta(days=31), + "USE_X_SENDFILE": False, + "SERVER_NAME": None, + "APPLICATION_ROOT": "/", + "SESSION_COOKIE_NAME": "session", + "SESSION_COOKIE_DOMAIN": None, + "SESSION_COOKIE_PATH": None, + "SESSION_COOKIE_HTTPONLY": True, + "SESSION_COOKIE_SECURE": False, + "SESSION_COOKIE_SAMESITE": None, + "SESSION_REFRESH_EACH_REQUEST": True, + "MAX_CONTENT_LENGTH": None, + "SEND_FILE_MAX_AGE_DEFAULT": None, + "TRAP_BAD_REQUEST_ERRORS": None, + "TRAP_HTTP_EXCEPTIONS": False, + "EXPLAIN_TEMPLATE_LOADING": False, + "PREFERRED_URL_SCHEME": "http", + "TEMPLATES_AUTO_RELOAD": None, + "MAX_COOKIE_SIZE": 4093, + } + ) + + #: The rule object to use for URL rules created. This is used by + #: :meth:`add_url_rule`. Defaults to :class:`werkzeug.routing.Rule`. + #: + #: .. versionadded:: 0.7 + url_rule_class = Rule + + #: The map object to use for storing the URL rules and routing + #: configuration parameters. Defaults to :class:`werkzeug.routing.Map`. + #: + #: .. versionadded:: 1.1.0 + url_map_class = Map + + #: The :meth:`test_client` method creates an instance of this test + #: client class. Defaults to :class:`~flask.testing.FlaskClient`. + #: + #: .. versionadded:: 0.7 + test_client_class: type[FlaskClient] | None = None + + #: The :class:`~click.testing.CliRunner` subclass, by default + #: :class:`~flask.testing.FlaskCliRunner` that is used by + #: :meth:`test_cli_runner`. Its ``__init__`` method should take a + #: Flask app object as the first argument. + #: + #: .. versionadded:: 1.0 + test_cli_runner_class: type[FlaskCliRunner] | None = None + + #: the session interface to use. By default an instance of + #: :class:`~flask.sessions.SecureCookieSessionInterface` is used here. + #: + #: .. versionadded:: 0.8 + session_interface: SessionInterface = SecureCookieSessionInterface() + + def __init__( + self, + import_name: str, + static_url_path: str | None = None, + static_folder: str | os.PathLike | None = "static", + static_host: str | None = None, + host_matching: bool = False, + subdomain_matching: bool = False, + template_folder: str | os.PathLike | None = "templates", + instance_path: str | None = None, + instance_relative_config: bool = False, + root_path: str | None = None, + ): + super().__init__( + import_name=import_name, + static_folder=static_folder, + static_url_path=static_url_path, + template_folder=template_folder, + root_path=root_path, + ) + + if instance_path is None: + instance_path = self.auto_find_instance_path() + elif not os.path.isabs(instance_path): + raise ValueError( + "If an instance path is provided it must be absolute." + " A relative path was given instead." + ) + + #: Holds the path to the instance folder. + #: + #: .. versionadded:: 0.8 + self.instance_path = instance_path + + #: The configuration dictionary as :class:`Config`. This behaves + #: exactly like a regular dictionary but supports additional methods + #: to load a config from files. + self.config = self.make_config(instance_relative_config) + + #: An instance of :attr:`aborter_class` created by + #: :meth:`make_aborter`. This is called by :func:`flask.abort` + #: to raise HTTP errors, and can be called directly as well. + #: + #: .. versionadded:: 2.2 + #: Moved from ``flask.abort``, which calls this object. + self.aborter = self.make_aborter() + + self.json: JSONProvider = self.json_provider_class(self) + """Provides access to JSON methods. Functions in ``flask.json`` + will call methods on this provider when the application context + is active. Used for handling JSON requests and responses. + + An instance of :attr:`json_provider_class`. Can be customized by + changing that attribute on a subclass, or by assigning to this + attribute afterwards. + + The default, :class:`~flask.json.provider.DefaultJSONProvider`, + uses Python's built-in :mod:`json` library. A different provider + can use a different JSON library. + + .. versionadded:: 2.2 + """ + + #: A list of functions that are called by + #: :meth:`handle_url_build_error` when :meth:`.url_for` raises a + #: :exc:`~werkzeug.routing.BuildError`. Each function is called + #: with ``error``, ``endpoint`` and ``values``. If a function + #: returns ``None`` or raises a ``BuildError``, it is skipped. + #: Otherwise, its return value is returned by ``url_for``. + #: + #: .. versionadded:: 0.9 + self.url_build_error_handlers: list[ + t.Callable[[Exception, str, dict[str, t.Any]], str] + ] = [] + + #: A list of functions that are called when the application context + #: is destroyed. Since the application context is also torn down + #: if the request ends this is the place to store code that disconnects + #: from databases. + #: + #: .. versionadded:: 0.9 + self.teardown_appcontext_funcs: list[ft.TeardownCallable] = [] + + #: A list of shell context processor functions that should be run + #: when a shell context is created. + #: + #: .. versionadded:: 0.11 + self.shell_context_processors: list[ft.ShellContextProcessorCallable] = [] + + #: Maps registered blueprint names to blueprint objects. The + #: dict retains the order the blueprints were registered in. + #: Blueprints can be registered multiple times, this dict does + #: not track how often they were attached. + #: + #: .. versionadded:: 0.7 + self.blueprints: dict[str, Blueprint] = {} + + #: a place where extensions can store application specific state. For + #: example this is where an extension could store database engines and + #: similar things. + #: + #: The key must match the name of the extension module. For example in + #: case of a "Flask-Foo" extension in `flask_foo`, the key would be + #: ``'foo'``. + #: + #: .. versionadded:: 0.7 + self.extensions: dict = {} + + #: 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 + + # Add a static route using the provided static_url_path, static_host, + # and static_folder if there is a configured static_folder. + # Note we do this without checking if static_folder exists. + # For one, it might be created while the server is running (e.g. during + # development). Also, Google App Engine stores static files somewhere + if self.has_static_folder: + assert ( + bool(static_host) == host_matching + ), "Invalid static_host/host_matching combination" + # Use a weakref to avoid creating a reference cycle between the app + # and the view function (see #3761). + self_ref = weakref.ref(self) + self.add_url_rule( + f"{self.static_url_path}/", + endpoint="static", + host=static_host, + view_func=lambda **kw: self_ref().send_static_file(**kw), # type: ignore # noqa: B950 + ) + + # Set the name of the Click group in case someone wants to add + # the app's commands to another CLI tool. + self.cli.name = self.name + + def _check_setup_finished(self, f_name: str) -> None: + if self._got_first_request: + raise AssertionError( + f"The setup method '{f_name}' can no longer be called" + " on the application. It has already handled its first" + " request, any changes will not be applied" + " consistently.\n" + "Make sure all imports, decorators, functions, etc." + " needed to set up the application are done before" + " running it." + ) + + @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 + + @cached_property + def logger(self) -> logging.Logger: + """A standard Python :class:`~logging.Logger` for the app, with + the same name as :attr:`name`. + + In debug mode, the logger's :attr:`~logging.Logger.level` will + be set to :data:`~logging.DEBUG`. + + If there are no handlers configured, a default handler will be + added. See :doc:`/logging` for more information. + + .. versionchanged:: 1.1.0 + The logger takes the same name as :attr:`name` rather than + hard-coding ``"flask.app"``. + + .. versionchanged:: 1.0.0 + Behavior was simplified. The logger is always named + ``"flask.app"``. The level is only set during configuration, + it doesn't check ``app.debug`` each time. Only one format is + used, not different ones depending on ``app.debug``. No + handlers are removed, and a handler is only added if no + handlers are already configured. + + .. versionadded:: 0.3 + """ + return create_logger(self) + + @cached_property + def jinja_env(self) -> Environment: + """The Jinja environment used to load templates. + + The environment is created the first time this property is + accessed. Changing :attr:`jinja_options` after that will have no + effect. + """ + return self.create_jinja_environment() + + @property + def got_first_request(self) -> bool: + """This attribute is set to ``True`` if the application started + handling the first request. + + .. deprecated:: 2.3 + Will be removed in Flask 2.4. + + .. versionadded:: 0.8 + """ + import warnings + + warnings.warn( + "'got_first_request' is deprecated and will be removed in Flask 2.4.", + DeprecationWarning, + stacklevel=2, + ) + 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["DEBUG"] = get_debug_flag() + return self.config_class(root_path, defaults) + + def make_aborter(self) -> Aborter: + """Create the object to assign to :attr:`aborter`. That object + is called by :func:`flask.abort` to raise HTTP errors, and can + be called directly as well. + + By default, this creates an instance of :attr:`aborter_class`, + which defaults to :class:`werkzeug.exceptions.Aborter`. + + .. versionadded:: 2.2 + """ + return self.aborter_class() + + def auto_find_instance_path(self) -> str: + """Tries to locate the instance path if it was not provided to the + constructor of the application class. It will basically calculate + the path to a folder named ``instance`` next to your main file or + the package. + + .. versionadded:: 0.8 + """ + prefix, package_path = find_package(self.import_name) + if prefix is None: + return os.path.join(package_path, "instance") + return os.path.join(prefix, "var", f"{self.name}-instance") + + def open_instance_resource(self, resource: str, mode: str = "rb") -> t.IO[t.AnyStr]: + """Opens a resource from the application's instance folder + (:attr:`instance_path`). Otherwise works like + :meth:`open_resource`. Instance resources can also be opened for + writing. + + :param resource: the name of the resource. To access resources within + subfolders use forward slashes as separator. + :param mode: resource file opening mode, default is 'rb'. + """ + return open(os.path.join(self.instance_path, resource), mode) + + def create_jinja_environment(self) -> Environment: + """Create the Jinja environment based on :attr:`jinja_options` + and the various Jinja-related methods of the app. Changing + :attr:`jinja_options` after this will have no effect. Also adds + Flask-related globals and filters to the environment. + + .. versionchanged:: 0.11 + ``Environment.auto_reload`` set in accordance with + ``TEMPLATES_AUTO_RELOAD`` configuration option. + + .. versionadded:: 0.5 + """ + options = dict(self.jinja_options) + + if "autoescape" not in options: + options["autoescape"] = self.select_jinja_autoescape + + if "auto_reload" not in options: + auto_reload = self.config["TEMPLATES_AUTO_RELOAD"] + + if auto_reload is None: + auto_reload = self.debug + + options["auto_reload"] = auto_reload + + rv = self.jinja_environment(self, **options) + rv.globals.update( + url_for=self.url_for, + get_flashed_messages=get_flashed_messages, + config=self.config, + # request, session and g are normally added with the + # context processor for efficiency reasons but for imported + # templates we also want the proxies in there. + request=request, + session=session, + g=g, + ) + rv.policies["json.dumps_function"] = self.json.dumps + return rv + + def create_global_jinja_loader(self) -> DispatchingJinjaLoader: + """Creates the loader for the Jinja2 environment. Can be used to + override just the loader and keeping the rest unchanged. It's + discouraged to override this function. Instead one should override + the :meth:`jinja_loader` function instead. + + The global loader dispatches between the loaders of the application + and the individual blueprints. + + .. versionadded:: 0.7 + """ + return DispatchingJinjaLoader(self) + + def select_jinja_autoescape(self, filename: str) -> bool: + """Returns ``True`` if autoescaping should be active for the given + template name. If no template name is given, returns `True`. + + .. versionchanged:: 2.2 + Autoescaping is now enabled by default for ``.svg`` files. + + .. versionadded:: 0.5 + """ + if filename is None: + return True + return filename.endswith((".html", ".htm", ".xml", ".xhtml", ".svg")) + + 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[str | None] = (None,) + + # A template may be rendered outside a request context. + if request: + names = chain(names, reversed(request.blueprints)) + + # The values passed to render_template take precedence. Keep a + # copy to re-apply after all context functions. + orig_ctx = context.copy() + + for name in names: + if name in self.template_context_processors: + for func in self.template_context_processors[name]: + context.update(func()) + + context.update(orig_ctx) + + def make_shell_context(self) -> dict: + """Returns the shell context for an interactive shell for this + application. This runs all the registered shell context + processors. + + .. versionadded:: 0.11 + """ + rv = {"app": self, "g": g} + for processor in self.shell_context_processors: + rv.update(processor()) + return rv + + @property + def debug(self) -> bool: + """Whether debug mode is enabled. When using ``flask run`` to start the + development server, an interactive debugger will be shown for unhandled + exceptions, and the server will be reloaded when code changes. This maps to the + :data:`DEBUG` config key. It may not behave as expected if set late. + + **Do not enable debug mode when deploying in production.** + + Default: ``False`` + """ + return self.config["DEBUG"] + + @debug.setter + def debug(self, value: bool) -> None: + self.config["DEBUG"] = value + + if self.config["TEMPLATES_AUTO_RELOAD"] is None: + self.jinja_env.auto_reload = value + + def run( + self, + host: str | None = None, + port: int | None = None, + debug: bool | None = None, + load_dotenv: bool = True, + **options: t.Any, + ) -> None: + """Runs the application on a local development server. + + Do not use ``run()`` in a production setting. It is not intended to + meet security and performance requirements for a production server. + Instead, see :doc:`/deploying/index` for WSGI server recommendations. + + If the :attr:`debug` flag is set the server will automatically reload + for code changes and show a debugger in case an exception happened. + + If you want to run the application in debug mode, but disable the + code execution on the interactive debugger, you can pass + ``use_evalex=False`` as parameter. This will keep the debugger's + traceback screen active, but disable code execution. + + It is not recommended to use this function for development with + automatic reloading as this is badly supported. Instead you should + be using the :command:`flask` command line script's ``run`` support. + + .. admonition:: Keep in Mind + + Flask will suppress any server error with a generic error page + unless it is in debug mode. As such to enable just the + interactive debugger without the code reloading, you have to + invoke :meth:`run` with ``debug=True`` and ``use_reloader=False``. + Setting ``use_debugger`` to ``True`` without being in debug mode + won't catch any exceptions because there won't be any to + catch. + + :param host: the hostname to listen on. Set this to ``'0.0.0.0'`` to + have the server available externally as well. Defaults to + ``'127.0.0.1'`` or the host in the ``SERVER_NAME`` config variable + if present. + :param port: the port of the webserver. Defaults to ``5000`` or the + port defined in the ``SERVER_NAME`` config variable if present. + :param debug: if given, enable or disable debug mode. See + :attr:`debug`. + :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv` + files to set environment variables. Will also change the working + directory to the directory containing the first file found. + :param options: the options to be forwarded to the underlying Werkzeug + server. See :func:`werkzeug.serving.run_simple` for more + information. + + .. versionchanged:: 1.0 + If installed, python-dotenv will be used to load environment + variables from :file:`.env` and :file:`.flaskenv` files. + + The :envvar:`FLASK_DEBUG` environment variable will override :attr:`debug`. + + Threaded mode is enabled by default. + + .. versionchanged:: 0.10 + The default port is now picked from the ``SERVER_NAME`` + variable. + """ + # Ignore this call so that it doesn't start another server if + # the 'flask run' command is used. + if os.environ.get("FLASK_RUN_FROM_CLI") == "true": + if not is_running_from_reloader(): + click.secho( + " * Ignoring a call to 'app.run()' that would block" + " the current 'flask' CLI command.\n" + " Only call 'app.run()' in an 'if __name__ ==" + ' "__main__"\' guard.', + fg="red", + ) + + return + + if get_load_dotenv(load_dotenv): + cli.load_dotenv() + + # if set, env var overrides existing value + if "FLASK_DEBUG" in os.environ: + self.debug = get_debug_flag() + + # debug passed to method overrides all other sources + if debug is not None: + self.debug = bool(debug) + + server_name = self.config.get("SERVER_NAME") + sn_host = sn_port = None + + if server_name: + sn_host, _, sn_port = server_name.partition(":") + + if not host: + if sn_host: + host = sn_host + else: + host = "127.0.0.1" + + if port or port == 0: + port = int(port) + elif sn_port: + port = int(sn_port) + else: + port = 5000 + + options.setdefault("use_reloader", self.debug) + options.setdefault("use_debugger", self.debug) + options.setdefault("threaded", True) + + cli.show_server_banner(self.debug, self.name) + + from werkzeug.serving import run_simple + + try: + run_simple(t.cast(str, host), port, self, **options) + finally: + # reset the first request information if the development server + # reset normally. This makes it possible to restart the server + # without reloader and that stuff from an interactive shell. + self._got_first_request = False + + def test_client(self, use_cookies: bool = True, **kwargs: t.Any) -> FlaskClient: + """Creates a test client for this application. For information + about unit testing head over to :doc:`/testing`. + + Note that if you are testing for assertions or exceptions in your + application code, you must set ``app.testing = True`` in order for the + exceptions to propagate to the test client. Otherwise, the exception + will be handled by the application (not visible to the test client) and + the only indication of an AssertionError or other exception will be a + 500 status code response to the test client. See the :attr:`testing` + attribute. For example:: + + app.testing = True + client = app.test_client() + + The test client can be used in a ``with`` block to defer the closing down + of the context until the end of the ``with`` block. This is useful if + you want to access the context locals for testing:: + + with app.test_client() as c: + rv = c.get('/?vodka=42') + assert request.args['vodka'] == '42' + + Additionally, you may pass optional keyword arguments that will then + be passed to the application's :attr:`test_client_class` constructor. + For example:: + + from flask.testing import FlaskClient + + class CustomClient(FlaskClient): + def __init__(self, *args, **kwargs): + self._authentication = kwargs.pop("authentication") + super(CustomClient,self).__init__( *args, **kwargs) + + app.test_client_class = CustomClient + client = app.test_client(authentication='Basic ....') + + See :class:`~flask.testing.FlaskClient` for more information. + + .. versionchanged:: 0.4 + added support for ``with`` block usage for the client. + + .. versionadded:: 0.7 + The `use_cookies` parameter was added as well as the ability + to override the client to be used by setting the + :attr:`test_client_class` attribute. + + .. versionchanged:: 0.11 + Added `**kwargs` to support passing additional keyword arguments to + the constructor of :attr:`test_client_class`. + """ + cls = self.test_client_class + if cls is None: + from .testing import FlaskClient as cls + return cls( # type: ignore + self, self.response_class, use_cookies=use_cookies, **kwargs + ) + + def test_cli_runner(self, **kwargs: t.Any) -> FlaskCliRunner: + """Create a CLI runner for testing CLI commands. + See :ref:`testing-cli`. + + Returns an instance of :attr:`test_cli_runner_class`, by default + :class:`~flask.testing.FlaskCliRunner`. The Flask app object is + passed as the first argument. + + .. versionadded:: 1.0 + """ + cls = self.test_cli_runner_class + + if cls is None: + from .testing import FlaskCliRunner as cls + + return cls(self, **kwargs) # type: ignore + + @setupmethod + def register_blueprint(self, blueprint: Blueprint, **options: t.Any) -> None: + """Register a :class:`~flask.Blueprint` on the application. Keyword + arguments passed to this method will override the defaults set on the + blueprint. + + Calls the blueprint's :meth:`~flask.Blueprint.register` method after + recording the blueprint in the application's :attr:`blueprints`. + + :param blueprint: The blueprint to register. + :param url_prefix: Blueprint routes will be prefixed with this. + :param subdomain: Blueprint routes will match on this subdomain. + :param url_defaults: Blueprint routes will use these default values for + view arguments. + :param options: Additional keyword arguments are passed to + :class:`~flask.blueprints.BlueprintSetupState`. They can be + accessed in :meth:`~flask.Blueprint.record` callbacks. + + .. versionchanged:: 2.0.1 + The ``name`` option can be used to change the (pre-dotted) + name the blueprint is registered with. This allows the same + blueprint to be registered multiple times with unique names + for ``url_for``. + + .. versionadded:: 0.7 + """ + blueprint.register(self, options) + + def iter_blueprints(self) -> t.ValuesView[Blueprint]: + """Iterates over all blueprints by the order they were registered. + + .. versionadded:: 0.11 + """ + return self.blueprints.values() + + @setupmethod + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + provide_automatic_options: bool | None = None, + **options: t.Any, + ) -> None: + if endpoint is None: + endpoint = _endpoint_from_view_func(view_func) # type: ignore + options["endpoint"] = endpoint + methods = options.pop("methods", None) + + # if the methods are not given and the view_func object knows its + # methods we can use that instead. If neither exists, we go with + # a tuple of only ``GET`` as default. + if methods is None: + methods = getattr(view_func, "methods", None) or ("GET",) + if isinstance(methods, str): + raise TypeError( + "Allowed methods must be a list of strings, for" + ' example: @app.route(..., methods=["POST"])' + ) + methods = {item.upper() for item in methods} + + # Methods that should always be added + required_methods = set(getattr(view_func, "required_methods", ())) + + # starting with Flask 0.8 the view_func object can disable and + # force-enable the automatic options handling. + if provide_automatic_options is None: + provide_automatic_options = getattr( + view_func, "provide_automatic_options", None + ) + + if provide_automatic_options is None: + if "OPTIONS" not in methods: + provide_automatic_options = True + required_methods.add("OPTIONS") + else: + provide_automatic_options = False + + # Add the required methods now. + methods |= required_methods + + rule = 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: str | None = None + ) -> t.Callable[[T_template_filter], T_template_filter]: + """A decorator that is used to register custom template filter. + You can specify a name for the filter, otherwise the function + name will be used. Example:: + + @app.template_filter() + def reverse(s): + return s[::-1] + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + + def decorator(f: T_template_filter) -> T_template_filter: + self.add_template_filter(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_filter( + self, f: ft.TemplateFilterCallable, name: str | None = None + ) -> None: + """Register a custom template filter. Works exactly like the + :meth:`template_filter` decorator. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + self.jinja_env.filters[name or f.__name__] = f + + @setupmethod + def template_test( + self, name: str | None = None + ) -> t.Callable[[T_template_test], T_template_test]: + """A decorator that is used to register custom template test. + You can specify a name for the test, otherwise the function + name will be used. Example:: + + @app.template_test() + def is_prime(n): + if n == 2: + return True + for i in range(2, int(math.ceil(math.sqrt(n))) + 1): + if n % i == 0: + return False + return True + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + + def decorator(f: T_template_test) -> T_template_test: + self.add_template_test(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_test( + self, f: ft.TemplateTestCallable, name: str | None = None + ) -> None: + """Register a custom template test. Works exactly like the + :meth:`template_test` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + self.jinja_env.tests[name or f.__name__] = f + + @setupmethod + def template_global( + self, name: str | None = None + ) -> t.Callable[[T_template_global], T_template_global]: + """A decorator that is used to register a custom template global function. + You can specify a name for the global function, otherwise the function + name will be used. Example:: + + @app.template_global() + def double(n): + return 2 * n + + .. versionadded:: 0.10 + + :param name: the optional name of the global function, otherwise the + function name will be used. + """ + + def decorator(f: T_template_global) -> T_template_global: + self.add_template_global(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_global( + self, f: ft.TemplateGlobalCallable, name: str | None = None + ) -> None: + """Register a custom template global function. Works exactly like the + :meth:`template_global` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the global function, otherwise the + function name will be used. + """ + self.jinja_env.globals[name or f.__name__] = f + + @setupmethod + def teardown_appcontext(self, f: T_teardown) -> T_teardown: + """Registers a function to be called when the application + context is popped. The application context is typically popped + after the request context for each request, at the end of CLI + commands, or after a manually pushed context ends. + + .. code-block:: python + + with app.app_context(): + ... + + When the ``with`` block exits (or ``ctx.pop()`` is called), the + teardown functions are called just before the app context is + made inactive. Since a request context typically also manages an + application context it would also be called when you pop a + request context. + + When a teardown function was called because of an unhandled + exception it will be passed an error object. If an + :meth:`errorhandler` is registered, it will handle the exception + and the teardown will not receive it. + + Teardown functions must avoid raising exceptions. If they + execute code that might fail they must surround that code with a + ``try``/``except`` block and log any errors. + + The return values of teardown functions are ignored. + + .. versionadded:: 0.9 + """ + self.teardown_appcontext_funcs.append(f) + return f + + @setupmethod + def shell_context_processor( + self, f: T_shell_context_processor + ) -> T_shell_context_processor: + """Registers a shell context processor function. + + .. versionadded:: 0.11 + """ + self.shell_context_processors.append(f) + return f + + def _find_error_handler(self, e: Exception) -> ft.ErrorHandlerCallable | None: + """Return a registered error handler for an exception in this order: + blueprint handler for a specific code, app handler for a specific code, + blueprint handler for an exception class, app handler for an exception + class, or ``None`` if a suitable handler is not found. + """ + exc_class, code = self._get_exc_class_and_code(type(e)) + names = (*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 + ) -> HTTPException | ft.ResponseReturnValue: + """Handles an HTTP exception. By default this will invoke the + registered error handlers and fall back to returning the + exception as response. + + .. versionchanged:: 1.0.3 + ``RoutingException``, used internally for actions such as + slash redirects during routing, is not passed to error + handlers. + + .. versionchanged:: 1.0 + Exceptions are looked up by code *and* by MRO, so + ``HTTPException`` subclasses can be handled with a catch-all + handler for the base ``HTTPException``. + + .. versionadded:: 0.3 + """ + # Proxy exceptions don't have error codes. We want to always return + # those unchanged as errors + if e.code is None: + return e + + # RoutingExceptions are used internally to trigger routing + # actions, such as slash redirects raising RequestRedirect. They + # are not raised or handled in user code. + if isinstance(e, RoutingException): + return e + + handler = self._find_error_handler(e) + if handler is None: + return e + return self.ensure_sync(handler)(e) + + def trap_http_exception(self, e: Exception) -> bool: + """Checks if an HTTP exception should be trapped or not. By default + this will return ``False`` for all exceptions except for a bad request + key error if ``TRAP_BAD_REQUEST_ERRORS`` is set to ``True``. It + also returns ``True`` if ``TRAP_HTTP_EXCEPTIONS`` is set to ``True``. + + This is called for all HTTP exceptions raised by a view function. + If it returns ``True`` for any exception the error handler for this + exception is not called and it shows up as regular exception in the + traceback. This is helpful for debugging implicitly raised HTTP + exceptions. + + .. versionchanged:: 1.0 + Bad request errors are not trapped by default in debug mode. + + .. versionadded:: 0.8 + """ + if self.config["TRAP_HTTP_EXCEPTIONS"]: + return True + + trap_bad_request = self.config["TRAP_BAD_REQUEST_ERRORS"] + + # if unset, trap key errors in debug mode + if ( + trap_bad_request is None + and self.debug + and isinstance(e, BadRequestKeyError) + ): + return True + + if trap_bad_request: + return isinstance(e, BadRequest) + + return False + + def handle_user_exception( + self, e: Exception + ) -> HTTPException | ft.ResponseReturnValue: + """This method is called whenever an exception occurs that + should be handled. A special case is :class:`~werkzeug + .exceptions.HTTPException` which is forwarded to the + :meth:`handle_http_exception` method. This function will either + return a response value or reraise the exception with the same + traceback. + + .. versionchanged:: 1.0 + Key errors raised from request data like ``form`` show the + bad key in debug mode rather than a generic bad request + message. + + .. versionadded:: 0.7 + """ + if isinstance(e, BadRequestKeyError) and ( + self.debug or self.config["TRAP_BAD_REQUEST_ERRORS"] + ): + e.show_exception = True + + if isinstance(e, HTTPException) and not self.trap_http_exception(e): + return self.handle_http_exception(e) + + handler = self._find_error_handler(e) + + if handler is None: + raise + + return self.ensure_sync(handler)(e) + + def handle_exception(self, e: Exception) -> Response: + """Handle an exception that did not have an error handler + associated with it, or that was raised from an error handler. + This always causes a 500 ``InternalServerError``. + + Always sends the :data:`got_request_exception` signal. + + If :data:`PROPAGATE_EXCEPTIONS` is ``True``, such as in debug + mode, the error will be re-raised so that the debugger can + display it. Otherwise, the original exception is logged, and + an :exc:`~werkzeug.exceptions.InternalServerError` is returned. + + If an error handler is registered for ``InternalServerError`` or + ``500``, it will be used. For consistency, the handler will + always receive the ``InternalServerError``. The original + unhandled exception is available as ``e.original_exception``. + + .. versionchanged:: 1.1.0 + Always passes the ``InternalServerError`` instance to the + handler, setting ``original_exception`` to the unhandled + error. + + .. versionchanged:: 1.1.0 + ``after_request`` functions and other finalization is done + even for the default 500 response when there is no handler. + + .. versionadded:: 0.3 + """ + exc_info = sys.exc_info() + got_request_exception.send(self, _async_wrapper=self.ensure_sync, exception=e) + propagate = self.config["PROPAGATE_EXCEPTIONS"] + + if propagate is None: + propagate = self.testing or self.debug + + if propagate: + # Re-raise if called with an active exception, otherwise + # raise the passed in exception. + if exc_info[1] is e: + raise + + raise e + + self.log_exception(exc_info) + server_error: InternalServerError | ft.ResponseReturnValue + server_error = InternalServerError(original_exception=e) + handler = self._find_error_handler(server_error) + + if handler is not None: + server_error = self.ensure_sync(handler)(server_error) + + return self.finalize_request(server_error, from_error_handler=True) + + def log_exception( + self, + exc_info: (tuple[type, BaseException, TracebackType] | tuple[None, None, None]), + ) -> None: + """Logs an exception. This is called by :meth:`handle_exception` + if debugging is disabled and right before the handler is called. + The default implementation logs the exception as error on the + :attr:`logger`. + + .. versionadded:: 0.8 + """ + self.logger.error( + f"Exception on {request.path} [{request.method}]", exc_info=exc_info + ) + + def raise_routing_exception(self, request: Request) -> t.NoReturn: + """Intercept routing exceptions and possibly do something else. + + In debug mode, intercept a routing redirect and replace it with + an error if the body will be discarded. + + With modern Werkzeug this shouldn't occur, since it now uses a + 308 status which tells the browser to resend the method and + body. + + .. versionchanged:: 2.1 + Don't intercept 307 and 308 redirects. + + :meta private: + :internal: + """ + if ( + not self.debug + or not isinstance(request.routing_exception, RequestRedirect) + or request.routing_exception.code in {307, 308} + or request.method in {"GET", "HEAD", "OPTIONS"} + ): + raise request.routing_exception # type: ignore + + from .debughelpers import FormDataRoutingRedirect + + raise FormDataRoutingRedirect(request) + + def dispatch_request(self) -> ft.ResponseReturnValue: + """Does the request dispatching. Matches the URL and returns the + return value of the view or error handler. This does not have to + be a response object. In order to convert the return value to a + proper response object, call :func:`make_response`. + + .. versionchanged:: 0.7 + This no longer does the exception handling, this code was + moved to the new :meth:`full_dispatch_request`. + """ + req = request_ctx.request + if req.routing_exception is not None: + self.raise_routing_exception(req) + rule: Rule = req.url_rule # type: ignore[assignment] + # if we provide automatic options for this URL and the + # request came with the OPTIONS method, reply automatically + if ( + getattr(rule, "provide_automatic_options", False) + and req.method == "OPTIONS" + ): + return self.make_default_options_response() + # otherwise dispatch to the handler for that endpoint + view_args: dict[str, t.Any] = req.view_args # type: ignore[assignment] + return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) + + def full_dispatch_request(self) -> Response: + """Dispatches the request and on top of that performs request + pre and postprocessing as well as HTTP exception catching and + error handling. + + .. versionadded:: 0.7 + """ + self._got_first_request = True + + try: + request_started.send(self, _async_wrapper=self.ensure_sync) + rv = self.preprocess_request() + if rv is None: + rv = self.dispatch_request() + except Exception as e: + rv = self.handle_user_exception(e) + return self.finalize_request(rv) + + def finalize_request( + self, + rv: ft.ResponseReturnValue | HTTPException, + from_error_handler: bool = False, + ) -> Response: + """Given the return value from a view function this finalizes + the request by converting it into a response and invoking the + postprocessing functions. This is invoked for both normal + request dispatching as well as error handlers. + + Because this means that it might be called as a result of a + failure a special safe mode is available which can be enabled + with the `from_error_handler` flag. If enabled, failures in + response processing will be logged and otherwise ignored. + + :internal: + """ + response = self.make_response(rv) + try: + response = self.process_response(response) + request_finished.send( + self, _async_wrapper=self.ensure_sync, response=response + ) + except Exception: + if not from_error_handler: + raise + self.logger.exception( + "Request finalizing failed with an error while handling an error" + ) + return response + + def make_default_options_response(self) -> Response: + """This method is called to create the default ``OPTIONS`` response. + This can be changed through subclassing to change the default + behavior of ``OPTIONS`` responses. + + .. versionadded:: 0.7 + """ + adapter = request_ctx.url_adapter + methods = adapter.allowed_methods() # type: ignore[union-attr] + rv = self.response_class() + rv.allow.update(methods) + return rv + + def should_ignore_error(self, error: BaseException | None) -> bool: + """This is called to figure out if an error should be ignored + or not as far as the teardown system is concerned. If this + function returns ``True`` then the teardown handlers will not be + passed the error. + + .. versionadded:: 0.10 + """ + return False + + def ensure_sync(self, func: t.Callable) -> t.Callable: + """Ensure that the function is synchronous for WSGI workers. + Plain ``def`` functions are returned as-is. ``async def`` + functions are wrapped to run and wait for the response. + + Override this method to change how the app runs async views. + + .. versionadded:: 2.0 + """ + if iscoroutinefunction(func): + return self.async_to_sync(func) + + return func + + def async_to_sync( + self, func: t.Callable[..., t.Coroutine] + ) -> t.Callable[..., t.Any]: + """Return a sync function that will run the coroutine function. + + .. code-block:: python + + result = app.async_to_sync(func)(*args, **kwargs) + + Override this method to change how the app converts async code + to be synchronously callable. + + .. versionadded:: 2.0 + """ + try: + from asgiref.sync import async_to_sync as asgiref_async_to_sync + except ImportError: + raise RuntimeError( + "Install Flask with the 'async' extra in order to use async views." + ) from None + + return asgiref_async_to_sync(func) + + def url_for( + self, + endpoint: str, + *, + _anchor: str | None = None, + _method: str | None = None, + _scheme: str | None = None, + _external: bool | None = None, + **values: t.Any, + ) -> str: + """Generate a URL to the given endpoint with the given values. + + This is called by :func:`flask.url_for`, and can be called + directly as well. + + An *endpoint* is the name of a URL rule, usually added with + :meth:`@app.route() `, and usually the same name as the + view function. A route defined in a :class:`~flask.Blueprint` + will prepend the blueprint's name separated by a ``.`` to the + endpoint. + + In some cases, such as email messages, you want URLs to include + the scheme and domain, like ``https://example.com/hello``. When + not in an active request, URLs will be external by default, but + this requires setting :data:`SERVER_NAME` so Flask knows what + domain to use. :data:`APPLICATION_ROOT` and + :data:`PREFERRED_URL_SCHEME` should also be configured as + needed. This config is only used when not in an active request. + + Functions can be decorated with :meth:`url_defaults` to modify + keyword arguments before the URL is built. + + If building fails for some reason, such as an unknown endpoint + or incorrect values, the app's :meth:`handle_url_build_error` + method is called. If that returns a string, that is returned, + otherwise a :exc:`~werkzeug.routing.BuildError` is raised. + + :param endpoint: The endpoint name associated with the URL to + generate. If this starts with a ``.``, the current blueprint + name (if any) will be used. + :param _anchor: If given, append this as ``#anchor`` to the URL. + :param _method: If given, generate the URL associated with this + method for the endpoint. + :param _scheme: If given, the URL will have this scheme if it + is external. + :param _external: If given, prefer the URL to be internal + (False) or require it to be external (True). External URLs + include the scheme and domain. When not in an active + request, URLs are external by default. + :param values: Values to use for the variable parts of the URL + rule. Unknown keys are appended as query string arguments, + like ``?a=b&c=d``. + + .. versionadded:: 2.2 + Moved from ``flask.url_for``, which calls this method. + """ + req_ctx = _cv_request.get(None) + + if req_ctx is not None: + url_adapter = req_ctx.url_adapter + blueprint_name = req_ctx.request.blueprint + + # If the endpoint starts with "." and the request matches a + # blueprint, the endpoint is relative to the blueprint. + if endpoint[:1] == ".": + if blueprint_name is not None: + endpoint = f"{blueprint_name}{endpoint}" + else: + endpoint = endpoint[1:] + + # When in a request, generate a URL without scheme and + # domain by default, unless a scheme is given. + if _external is None: + _external = _scheme is not None + else: + app_ctx = _cv_app.get(None) + + # If called by helpers.url_for, an app context is active, + # use its url_adapter. Otherwise, app.url_for was called + # directly, build an adapter. + if app_ctx is not None: + url_adapter = app_ctx.url_adapter + else: + url_adapter = self.create_url_adapter(None) + + if url_adapter is None: + raise RuntimeError( + "Unable to build URLs outside an active request" + " without 'SERVER_NAME' configured. Also configure" + " 'APPLICATION_ROOT' and 'PREFERRED_URL_SCHEME' as" + " needed." + ) + + # When outside a request, generate a URL with scheme and + # domain by default. + if _external is None: + _external = True + + # It is an error to set _scheme when _external=False, in order + # to avoid accidental insecure URLs. + if _scheme is not None and not _external: + raise ValueError("When specifying '_scheme', '_external' must be True.") + + self.inject_url_defaults(endpoint, values) + + try: + rv = url_adapter.build( # type: ignore[union-attr] + endpoint, + values, + method=_method, + url_scheme=_scheme, + force_external=_external, + ) + except BuildError as error: + values.update( + _anchor=_anchor, _method=_method, _scheme=_scheme, _external=_external + ) + return self.handle_url_build_error(error, endpoint, values) + + if _anchor is not None: + _anchor = _url_quote(_anchor, safe="%!#$&'()*+,/:;=?@") + rv = f"{rv}#{_anchor}" + + return rv + + def redirect(self, location: str, code: int = 302) -> BaseResponse: + """Create a redirect response object. + + This is called by :func:`flask.redirect`, and can be called + directly as well. + + :param location: The URL to redirect to. + :param code: The status code for the redirect. + + .. versionadded:: 2.2 + Moved from ``flask.redirect``, which calls this method. + """ + return _wz_redirect(location, code=code, Response=self.response_class) + + def make_response(self, rv: ft.ResponseReturnValue) -> Response: + """Convert the return value from a view function to an instance of + :attr:`response_class`. + + :param rv: the return value from the view function. The view function + must return a response. Returning ``None``, or the view ending + without returning, is not allowed. The following types are allowed + for ``view_rv``: + + ``str`` + A response object is created with the string encoded to UTF-8 + as the body. + + ``bytes`` + A response object is created with the bytes as the body. + + ``dict`` + A dictionary that will be jsonify'd before being returned. + + ``list`` + A list that will be jsonify'd before being returned. + + ``generator`` or ``iterator`` + A generator that returns ``str`` or ``bytes`` to be + streamed as the response. + + ``tuple`` + Either ``(body, status, headers)``, ``(body, status)``, or + ``(body, headers)``, where ``body`` is any of the other types + allowed here, ``status`` is a string or an integer, and + ``headers`` is a dictionary or a list of ``(key, value)`` + tuples. If ``body`` is a :attr:`response_class` instance, + ``status`` overwrites the exiting value and ``headers`` are + extended. + + :attr:`response_class` + The object is returned unchanged. + + other :class:`~werkzeug.wrappers.Response` class + The object is coerced to :attr:`response_class`. + + :func:`callable` + The function is called as a WSGI application. The result is + used to create a response object. + + .. versionchanged:: 2.2 + A generator will be converted to a streaming response. + A list will be converted to a JSON response. + + .. versionchanged:: 1.1 + A dict will be converted to a JSON response. + + .. versionchanged:: 0.9 + Previously a tuple was interpreted as the arguments for the + response object. + """ + + status = headers = None + + # unpack tuple returns + if isinstance(rv, tuple): + len_rv = len(rv) + + # a 3-tuple is unpacked directly + if len_rv == 3: + rv, status, headers = rv # type: ignore[misc] + # decide if a 2-tuple has status or headers + elif len_rv == 2: + if isinstance(rv[1], (Headers, dict, tuple, list)): + rv, headers = rv + else: + rv, status = rv # type: ignore[assignment,misc] + # other sized tuples are not allowed + else: + raise TypeError( + "The view function did not return a valid response tuple." + " The tuple must have the form (body, status, headers)," + " (body, status), or (body, headers)." + ) + + # the body must not be None + if rv is None: + raise TypeError( + f"The view function for {request.endpoint!r} did not" + " return a valid response. The function either returned" + " None or ended without a return statement." + ) + + # make sure the body is an instance of the response class + if not isinstance(rv, self.response_class): + if isinstance(rv, (str, bytes, bytearray)) or isinstance(rv, _abc_Iterator): + # let the response class set the status and headers instead of + # waiting to do it manually, so that the class can handle any + # special logic + rv = self.response_class( + rv, + status=status, + headers=headers, # type: ignore[arg-type] + ) + status = headers = None + elif isinstance(rv, (dict, list)): + rv = self.json.response(rv) + elif isinstance(rv, BaseResponse) or callable(rv): + # evaluate a WSGI callable, or coerce a different response + # class to the correct type + try: + rv = self.response_class.force_type( + rv, request.environ # type: ignore[arg-type] + ) + except TypeError as e: + raise TypeError( + f"{e}\nThe view function did not return a valid" + " response. The return type must be a string," + " dict, list, tuple with headers or status," + " Response instance, or WSGI callable, but it" + f" was a {type(rv).__name__}." + ).with_traceback(sys.exc_info()[2]) from None + else: + raise TypeError( + "The view function did not return a valid" + " response. The return type must be a string," + " dict, list, tuple with headers or status," + " Response instance, or WSGI callable, but it was a" + f" {type(rv).__name__}." + ) + + rv = t.cast(Response, rv) + # prefer the status if it was provided + if status is not None: + if isinstance(status, (str, bytes, bytearray)): + rv.status = status + else: + rv.status_code = status + + # extend existing headers with provided headers + if headers: + rv.headers.update(headers) # type: ignore[arg-type] + + return rv + + def create_url_adapter(self, request: Request | None) -> MapAdapter | None: + """Creates a URL adapter for the given request. The URL adapter + is created at a point where the request context is not yet set + up so the request is passed explicitly. + + .. versionadded:: 0.6 + + .. versionchanged:: 0.9 + This can now also be called without a request object when the + URL adapter is created for the application context. + + .. versionchanged:: 1.0 + :data:`SERVER_NAME` no longer implicitly enables subdomain + matching. Use :attr:`subdomain_matching` instead. + """ + if request is not None: + # If subdomain matching is disabled (the default), use the + # default subdomain in all cases. This should be the default + # in Werkzeug but it currently does not have that feature. + if not self.subdomain_matching: + subdomain = self.url_map.default_subdomain or None + else: + subdomain = None + + return self.url_map.bind_to_environ( + request.environ, + server_name=self.config["SERVER_NAME"], + subdomain=subdomain, + ) + # We need at the very least the server name to be set for this + # to work. + if self.config["SERVER_NAME"] is not None: + return self.url_map.bind( + self.config["SERVER_NAME"], + script_name=self.config["APPLICATION_ROOT"], + url_scheme=self.config["PREFERRED_URL_SCHEME"], + ) + + return None + + def 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[str | None] = (None,) + + # url_for may be called outside a request context, parse the + # passed endpoint instead of using request.blueprints. + if "." in endpoint: + names = chain( + names, reversed(_split_blueprint_path(endpoint.rpartition(".")[0])) + ) + + for name in names: + if name in self.url_default_functions: + for func in self.url_default_functions[name]: + func(endpoint, values) + + def handle_url_build_error( + self, error: BuildError, endpoint: str, values: dict[str, t.Any] + ) -> str: + """Called by :meth:`.url_for` if a + :exc:`~werkzeug.routing.BuildError` was raised. If this returns + a value, it will be returned by ``url_for``, otherwise the error + will be re-raised. + + Each function in :attr:`url_build_error_handlers` is called with + ``error``, ``endpoint`` and ``values``. If a function returns + ``None`` or raises a ``BuildError``, it is skipped. Otherwise, + its return value is returned by ``url_for``. + + :param error: The active ``BuildError`` being handled. + :param endpoint: The endpoint being built. + :param values: The keyword arguments passed to ``url_for``. + """ + for handler in self.url_build_error_handlers: + try: + rv = handler(error, endpoint, values) + except BuildError as e: + # make error available outside except block + error = e + else: + if rv is not None: + return rv + + # Re-raise if called with an active exception, otherwise raise + # the passed in exception. + if error is sys.exc_info()[1]: + raise + + raise error + + def preprocess_request(self) -> ft.ResponseReturnValue | None: + """Called before the request is dispatched. Calls + :attr:`url_value_preprocessors` registered with the app and the + current blueprint (if any). Then calls :attr:`before_request_funcs` + registered with the app and the blueprint. + + If any :meth:`before_request` handler returns a non-None value, the + value is handled as if it was the return value from the view, and + further request handling is stopped. + """ + names = (None, *reversed(request.blueprints)) + + for name in names: + if name in self.url_value_preprocessors: + for url_func in self.url_value_preprocessors[name]: + url_func(request.endpoint, request.view_args) + + for name in names: + if name in self.before_request_funcs: + for before_func in self.before_request_funcs[name]: + rv = self.ensure_sync(before_func)() + + if rv is not None: + return rv + + return None + + def process_response(self, response: Response) -> Response: + """Can be overridden in order to modify the response object + before it's sent to the WSGI server. By default this will + call all the :meth:`after_request` decorated functions. + + .. versionchanged:: 0.5 + As of Flask 0.5 the functions registered for after request + execution are called in reverse order of registration. + + :param response: a :attr:`response_class` object. + :return: a new response object or the same, has to be an + instance of :attr:`response_class`. + """ + ctx = request_ctx._get_current_object() # type: ignore[attr-defined] + + for func in ctx._after_request_functions: + response = self.ensure_sync(func)(response) + + for name in chain(request.blueprints, (None,)): + if name in self.after_request_funcs: + for func in reversed(self.after_request_funcs[name]): + response = self.ensure_sync(func)(response) + + if not self.session_interface.is_null_session(ctx.session): + self.session_interface.save_session(self, ctx.session, response) + + return response + + def do_teardown_request( + self, exc: BaseException | None = _sentinel # type: ignore + ) -> None: + """Called after the request is dispatched and the response is + returned, right before the request context is popped. + + This calls all functions decorated with + :meth:`teardown_request`, and :meth:`Blueprint.teardown_request` + if a blueprint handled the request. Finally, the + :data:`request_tearing_down` signal is sent. + + This is called by + :meth:`RequestContext.pop() `, + which may be delayed during testing to maintain access to + resources. + + :param exc: An unhandled exception raised while dispatching the + request. Detected from the current exception information if + not passed. Passed to each teardown function. + + .. versionchanged:: 0.9 + Added the ``exc`` argument. + """ + if exc is _sentinel: + exc = sys.exc_info()[1] + + for name in chain(request.blueprints, (None,)): + if name in self.teardown_request_funcs: + for func in reversed(self.teardown_request_funcs[name]): + self.ensure_sync(func)(exc) + + request_tearing_down.send(self, _async_wrapper=self.ensure_sync, exc=exc) + + def do_teardown_appcontext( + self, exc: BaseException | None = _sentinel # type: ignore + ) -> None: + """Called right before the application context is popped. + + When handling a request, the application context is popped + after the request context. See :meth:`do_teardown_request`. + + This calls all functions decorated with + :meth:`teardown_appcontext`. Then the + :data:`appcontext_tearing_down` signal is sent. + + This is called by + :meth:`AppContext.pop() `. + + .. versionadded:: 0.9 + """ + if exc is _sentinel: + exc = sys.exc_info()[1] + + for func in reversed(self.teardown_appcontext_funcs): + self.ensure_sync(func)(exc) + + appcontext_tearing_down.send(self, _async_wrapper=self.ensure_sync, exc=exc) + + def app_context(self) -> AppContext: + """Create an :class:`~flask.ctx.AppContext`. Use as a ``with`` + block to push the context, which will make :data:`current_app` + point at this application. + + An application context is automatically pushed by + :meth:`RequestContext.push() ` + when handling a request, and when running a CLI command. Use + this to manually create a context outside of these situations. + + :: + + with app.app_context(): + init_db() + + See :doc:`/appcontext`. + + .. versionadded:: 0.9 + """ + return AppContext(self) + + def request_context(self, environ: 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 app.test_request_context(...): + generate_report() + + When using the shell, it may be easier to push and pop the + context manually to avoid indentation. :: + + ctx = app.test_request_context(...) + ctx.push() + ... + ctx.pop() + + Takes the same arguments as Werkzeug's + :class:`~werkzeug.test.EnvironBuilder`, with some defaults from + the application. See the linked Werkzeug docs for most of the + available arguments. Flask-specific behavior is listed here. + + :param path: URL path being requested. + :param base_url: Base URL where the app is being served, which + ``path`` is relative to. If not given, built from + :data:`PREFERRED_URL_SCHEME`, ``subdomain``, + :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`. + :param subdomain: Subdomain name to append to + :data:`SERVER_NAME`. + :param url_scheme: Scheme to use instead of + :data:`PREFERRED_URL_SCHEME`. + :param data: The request body, either as a string or a dict of + form keys and values. + :param json: If given, this is serialized as JSON and passed as + ``data``. Also defaults ``content_type`` to + ``application/json``. + :param args: other positional arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + :param kwargs: other keyword arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + """ + from .testing import EnvironBuilder + + builder = EnvironBuilder(self, *args, **kwargs) + + try: + return self.request_context(builder.get_environ()) + finally: + builder.close() + + def wsgi_app(self, environ: 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: BaseException | None = None + try: + try: + ctx.push() + response = self.full_dispatch_request() + except Exception as e: + error = e + response = self.handle_exception(e) + except: # noqa: B001 + error = sys.exc_info()[1] + raise + return response(environ, start_response) + finally: + if "werkzeug.debug.preserve_context" in environ: + environ["werkzeug.debug.preserve_context"](_cv_app.get()) + environ["werkzeug.debug.preserve_context"](_cv_request.get()) + + if error is not None and self.should_ignore_error(error): + error = None + + ctx.pop(error) + + def __call__(self, environ: 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/.venv/Lib/site-packages/flask/blueprints.py b/.venv/Lib/site-packages/flask/blueprints.py new file mode 100644 index 000000000..0407f86fe --- /dev/null +++ b/.venv/Lib/site-packages/flask/blueprints.py @@ -0,0 +1,626 @@ +from __future__ import annotations + +import os +import typing as t +from collections import defaultdict +from functools import update_wrapper + +from . import typing as ft +from .scaffold import _endpoint_from_view_func +from .scaffold import _sentinel +from .scaffold import Scaffold +from .scaffold import setupmethod + +if t.TYPE_CHECKING: # pragma: no cover + from .app import Flask + +DeferredSetupFunction = t.Callable[["BlueprintSetupState"], t.Callable] +T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable) +T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable) +T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable) +T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) +T_template_context_processor = t.TypeVar( + "T_template_context_processor", bound=ft.TemplateContextProcessorCallable +) +T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) +T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) +T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) +T_url_defaults = t.TypeVar("T_url_defaults", bound=ft.URLDefaultCallable) +T_url_value_preprocessor = t.TypeVar( + "T_url_value_preprocessor", bound=ft.URLValuePreprocessorCallable +) + + +class BlueprintSetupState: + """Temporary holder object for registering a blueprint with the + application. An instance of this class is created by the + :meth:`~flask.Blueprint.make_setup_state` method and later passed + to all register callback functions. + """ + + def __init__( + self, + blueprint: Blueprint, + app: Flask, + options: t.Any, + first_registration: bool, + ) -> None: + #: a reference to the current application + self.app = app + + #: a reference to the blueprint that created this setup state. + self.blueprint = blueprint + + #: a dictionary with all options that were passed to the + #: :meth:`~flask.Flask.register_blueprint` method. + self.options = options + + #: as blueprints can be registered multiple times with the + #: application and not everything wants to be registered + #: multiple times on it, this attribute can be used to figure + #: out if the blueprint was registered in the past already. + self.first_registration = first_registration + + subdomain = self.options.get("subdomain") + if subdomain is None: + subdomain = self.blueprint.subdomain + + #: The subdomain that the blueprint should be active for, ``None`` + #: otherwise. + self.subdomain = subdomain + + url_prefix = self.options.get("url_prefix") + if url_prefix is None: + url_prefix = self.blueprint.url_prefix + #: The prefix that should be used for all URLs defined on the + #: blueprint. + self.url_prefix = url_prefix + + self.name = self.options.get("name", blueprint.name) + self.name_prefix = self.options.get("name_prefix", "") + + #: A dictionary with URL defaults that is added to each and every + #: URL that was defined with the blueprint. + self.url_defaults = dict(self.blueprint.url_values_defaults) + self.url_defaults.update(self.options.get("url_defaults", ())) + + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: t.Callable | None = None, + **options: t.Any, + ) -> None: + """A helper method to register a rule (and optionally a view function) + to the application. The endpoint is automatically prefixed with the + blueprint's name. + """ + if self.url_prefix is not None: + if rule: + rule = "/".join((self.url_prefix.rstrip("/"), rule.lstrip("/"))) + else: + rule = self.url_prefix + options.setdefault("subdomain", self.subdomain) + if endpoint is None: + endpoint = _endpoint_from_view_func(view_func) # type: ignore + defaults = self.url_defaults + if "defaults" in options: + defaults = dict(defaults, **options.pop("defaults")) + + self.app.add_url_rule( + rule, + f"{self.name_prefix}.{self.name}.{endpoint}".lstrip("."), + view_func, + defaults=defaults, + **options, + ) + + +class Blueprint(Scaffold): + """Represents a blueprint, a collection of routes and other + app-related functions that can be registered on a real application + later. + + A blueprint is an object that allows defining application functions + without requiring an application object ahead of time. It uses the + same decorators as :class:`~flask.Flask`, but defers the need for an + application by recording them for later registration. + + Decorating a function with a blueprint creates a deferred function + that is called with :class:`~flask.blueprints.BlueprintSetupState` + when the blueprint is registered on an application. + + See :doc:`/blueprints` for more information. + + :param name: The name of the blueprint. Will be prepended to each + endpoint name. + :param import_name: The name of the blueprint package, usually + ``__name__``. This helps locate the ``root_path`` for the + blueprint. + :param static_folder: A folder with static files that should be + served by the blueprint's static route. The path is relative to + the blueprint's root path. Blueprint static files are disabled + by default. + :param static_url_path: The url to serve static files from. + Defaults to ``static_folder``. If the blueprint does not have + a ``url_prefix``, the app's static route will take precedence, + and the blueprint's static files won't be accessible. + :param template_folder: A folder with templates that should be added + to the app's template search path. The path is relative to the + blueprint's root path. Blueprint templates are disabled by + default. Blueprint templates have a lower precedence than those + in the app's templates folder. + :param url_prefix: A path to prepend to all of the blueprint's URLs, + to make them distinct from the rest of the app's routes. + :param subdomain: A subdomain that blueprint routes will match on by + default. + :param url_defaults: A dict of default values that blueprint routes + will receive by default. + :param root_path: By default, the blueprint will automatically set + this based on ``import_name``. In certain situations this + automatic detection can fail, so the path can be specified + manually instead. + + .. versionchanged:: 1.1.0 + Blueprints have a ``cli`` group to register nested CLI commands. + The ``cli_group`` parameter controls the name of the group under + the ``flask`` command. + + .. versionadded:: 0.7 + """ + + _got_registered_once = False + + def __init__( + self, + name: str, + import_name: str, + static_folder: str | os.PathLike | None = None, + static_url_path: str | None = None, + template_folder: str | os.PathLike | None = None, + url_prefix: str | None = None, + subdomain: str | None = None, + url_defaults: dict | None = None, + root_path: str | None = None, + cli_group: str | None = _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 not name: + raise ValueError("'name' may not be empty.") + + if "." in name: + raise ValueError("'name' may not contain a dot '.' character.") + + self.name = name + self.url_prefix = url_prefix + self.subdomain = subdomain + self.deferred_functions: list[DeferredSetupFunction] = [] + + if url_defaults is None: + url_defaults = {} + + self.url_values_defaults = url_defaults + self.cli_group = cli_group + self._blueprints: list[tuple[Blueprint, dict]] = [] + + def _check_setup_finished(self, f_name: str) -> None: + if self._got_registered_once: + raise AssertionError( + f"The setup method '{f_name}' can no longer be called on the blueprint" + f" '{self.name}'. It has already been registered at least once, any" + " changes will not be applied consistently.\n" + "Make sure all imports, decorators, functions, etc. needed to set up" + " the blueprint are done before registering it." + ) + + @setupmethod + def record(self, func: t.Callable) -> None: + """Registers a function that is called when the blueprint is + registered on the application. This function is called with the + state as argument as returned by the :meth:`make_setup_state` + method. + """ + self.deferred_functions.append(func) + + @setupmethod + def record_once(self, func: t.Callable) -> None: + """Works like :meth:`record` but wraps the function in another + function that will ensure the function is only called once. If the + blueprint is registered a second time on the application, the + function passed is not called. + """ + + def wrapper(state: BlueprintSetupState) -> None: + if state.first_registration: + func(state) + + self.record(update_wrapper(wrapper, func)) + + def make_setup_state( + self, app: Flask, options: dict, first_registration: bool = False + ) -> BlueprintSetupState: + """Creates an instance of :meth:`~flask.blueprints.BlueprintSetupState` + object that is later passed to the register callback functions. + Subclasses can override this to return a subclass of the setup state. + """ + return BlueprintSetupState(self, app, options, first_registration) + + @setupmethod + def register_blueprint(self, blueprint: Blueprint, **options: t.Any) -> None: + """Register a :class:`~flask.Blueprint` on this blueprint. Keyword + arguments passed to this method will override the defaults set + on the blueprint. + + .. versionchanged:: 2.0.1 + The ``name`` option can be used to change the (pre-dotted) + name the blueprint is registered with. This allows the same + blueprint to be registered multiple times with unique names + for ``url_for``. + + .. versionadded:: 2.0 + """ + if blueprint is self: + raise ValueError("Cannot register a blueprint on itself") + self._blueprints.append((blueprint, options)) + + def register(self, app: Flask, options: dict) -> None: + """Called by :meth:`Flask.register_blueprint` to register all + views and callbacks registered on the blueprint with the + application. Creates a :class:`.BlueprintSetupState` and calls + each :meth:`record` callback with it. + + :param app: The application this blueprint is being registered + with. + :param options: Keyword arguments forwarded from + :meth:`~Flask.register_blueprint`. + + .. versionchanged:: 2.3 + Nested blueprints now correctly apply subdomains. + + .. versionchanged:: 2.1 + Registering the same blueprint with the same name multiple + times is an error. + + .. versionchanged:: 2.0.1 + Nested blueprints are registered with their dotted name. + This allows different blueprints with the same name to be + nested at different locations. + + .. versionchanged:: 2.0.1 + The ``name`` option can be used to change the (pre-dotted) + name the blueprint is registered with. This allows the same + blueprint to be registered multiple times with unique names + for ``url_for``. + """ + name_prefix = options.get("name_prefix", "") + self_name = options.get("name", self.name) + name = f"{name_prefix}.{self_name}".lstrip(".") + + if name in app.blueprints: + bp_desc = "this" if app.blueprints[name] is self else "a different" + existing_at = f" '{name}'" if self_name != name else "" + + raise ValueError( + f"The name '{self_name}' is already registered for" + f" {bp_desc} blueprint{existing_at}. Use 'name=' to" + f" provide a unique name." + ) + + first_bp_registration = not any(bp is self for bp in app.blueprints.values()) + first_name_registration = name not in app.blueprints + + app.blueprints[name] = self + self._got_registered_once = True + state = self.make_setup_state(app, options, first_bp_registration) + + if self.has_static_folder: + state.add_url_rule( + f"{self.static_url_path}/", + view_func=self.send_static_file, + 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") + bp_subdomain = bp_options.get("subdomain") + + if bp_subdomain is None: + bp_subdomain = blueprint.subdomain + + if state.subdomain is not None and bp_subdomain is not None: + bp_options["subdomain"] = bp_subdomain + "." + state.subdomain + elif bp_subdomain is not None: + bp_options["subdomain"] = bp_subdomain + elif state.subdomain is not None: + bp_options["subdomain"] = state.subdomain + + if bp_url_prefix is None: + bp_url_prefix = blueprint.url_prefix + + if state.url_prefix is not None and bp_url_prefix is not None: + bp_options["url_prefix"] = ( + state.url_prefix.rstrip("/") + "/" + bp_url_prefix.lstrip("/") + ) + elif bp_url_prefix is not None: + bp_options["url_prefix"] = bp_url_prefix + elif state.url_prefix is not None: + bp_options["url_prefix"] = state.url_prefix + + bp_options["name_prefix"] = name + blueprint.register(app, bp_options) + + @setupmethod + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + provide_automatic_options: bool | None = None, + **options: t.Any, + ) -> None: + """Register a URL rule with the blueprint. See :meth:`.Flask.add_url_rule` for + full documentation. + + The URL rule is prefixed with the blueprint's URL prefix. The endpoint name, + used with :func:`url_for`, is prefixed with the blueprint's name. + """ + if endpoint and "." in endpoint: + raise ValueError("'endpoint' may not contain a dot '.' character.") + + if view_func and hasattr(view_func, "__name__") and "." in view_func.__name__: + raise ValueError("'view_func' name may not contain a dot '.' character.") + + self.record( + lambda s: s.add_url_rule( + rule, + endpoint, + view_func, + provide_automatic_options=provide_automatic_options, + **options, + ) + ) + + @setupmethod + def app_template_filter( + self, name: str | None = None + ) -> t.Callable[[T_template_filter], T_template_filter]: + """Register a template filter, available in any template rendered by the + application. Equivalent to :meth:`.Flask.template_filter`. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + + def decorator(f: T_template_filter) -> T_template_filter: + self.add_app_template_filter(f, name=name) + return f + + return decorator + + @setupmethod + def add_app_template_filter( + self, f: ft.TemplateFilterCallable, name: str | None = None + ) -> None: + """Register a template filter, available in any template rendered by the + application. Works like the :meth:`app_template_filter` decorator. Equivalent to + :meth:`.Flask.add_template_filter`. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + + def register_template(state: BlueprintSetupState) -> None: + state.app.jinja_env.filters[name or f.__name__] = f + + self.record_once(register_template) + + @setupmethod + def app_template_test( + self, name: str | None = None + ) -> t.Callable[[T_template_test], T_template_test]: + """Register a template test, available in any template rendered by the + application. Equivalent to :meth:`.Flask.template_test`. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + + def decorator(f: T_template_test) -> T_template_test: + self.add_app_template_test(f, name=name) + return f + + return decorator + + @setupmethod + def add_app_template_test( + self, f: ft.TemplateTestCallable, name: str | None = None + ) -> None: + """Register a template test, available in any template rendered by the + application. Works like the :meth:`app_template_test` decorator. Equivalent to + :meth:`.Flask.add_template_test`. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + + def register_template(state: BlueprintSetupState) -> None: + state.app.jinja_env.tests[name or f.__name__] = f + + self.record_once(register_template) + + @setupmethod + def app_template_global( + self, name: str | None = None + ) -> t.Callable[[T_template_global], T_template_global]: + """Register a template global, available in any template rendered by the + application. Equivalent to :meth:`.Flask.template_global`. + + .. versionadded:: 0.10 + + :param name: the optional name of the global, otherwise the + function name will be used. + """ + + def decorator(f: T_template_global) -> T_template_global: + self.add_app_template_global(f, name=name) + return f + + return decorator + + @setupmethod + def add_app_template_global( + self, f: ft.TemplateGlobalCallable, name: str | None = None + ) -> None: + """Register a template global, available in any template rendered by the + application. Works like the :meth:`app_template_global` decorator. Equivalent to + :meth:`.Flask.add_template_global`. + + .. versionadded:: 0.10 + + :param name: the optional name of the global, otherwise the + function name will be used. + """ + + def register_template(state: BlueprintSetupState) -> None: + state.app.jinja_env.globals[name or f.__name__] = f + + self.record_once(register_template) + + @setupmethod + def before_app_request(self, f: T_before_request) -> T_before_request: + """Like :meth:`before_request`, but before every request, not only those handled + by the blueprint. Equivalent to :meth:`.Flask.before_request`. + """ + self.record_once( + lambda s: s.app.before_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def after_app_request(self, f: T_after_request) -> T_after_request: + """Like :meth:`after_request`, but after every request, not only those handled + by the blueprint. Equivalent to :meth:`.Flask.after_request`. + """ + self.record_once( + lambda s: s.app.after_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def teardown_app_request(self, f: T_teardown) -> T_teardown: + """Like :meth:`teardown_request`, but after every request, not only those + handled by the blueprint. Equivalent to :meth:`.Flask.teardown_request`. + """ + self.record_once( + lambda s: s.app.teardown_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_context_processor( + self, f: T_template_context_processor + ) -> T_template_context_processor: + """Like :meth:`context_processor`, but for templates rendered by every view, not + only by the blueprint. Equivalent to :meth:`.Flask.context_processor`. + """ + self.record_once( + lambda s: s.app.template_context_processors.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_errorhandler( + self, code: type[Exception] | int + ) -> t.Callable[[T_error_handler], T_error_handler]: + """Like :meth:`errorhandler`, but for every request, not only those handled by + the blueprint. Equivalent to :meth:`.Flask.errorhandler`. + """ + + def decorator(f: T_error_handler) -> T_error_handler: + self.record_once(lambda s: s.app.errorhandler(code)(f)) + return f + + return decorator + + @setupmethod + def app_url_value_preprocessor( + self, f: T_url_value_preprocessor + ) -> T_url_value_preprocessor: + """Like :meth:`url_value_preprocessor`, but for every request, not only those + handled by the blueprint. Equivalent to :meth:`.Flask.url_value_preprocessor`. + """ + self.record_once( + lambda s: s.app.url_value_preprocessors.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_url_defaults(self, f: T_url_defaults) -> T_url_defaults: + """Like :meth:`url_defaults`, but for every request, not only those handled by + the blueprint. Equivalent to :meth:`.Flask.url_defaults`. + """ + self.record_once( + lambda s: s.app.url_default_functions.setdefault(None, []).append(f) + ) + return f diff --git a/.venv/Lib/site-packages/flask/cli.py b/.venv/Lib/site-packages/flask/cli.py new file mode 100644 index 000000000..f7e1f2935 --- /dev/null +++ b/.venv/Lib/site-packages/flask/cli.py @@ -0,0 +1,1067 @@ +from __future__ import annotations + +import ast +import inspect +import os +import platform +import re +import sys +import traceback +import typing as t +from functools import update_wrapper +from operator import itemgetter + +import click +from click.core import ParameterSource +from werkzeug import run_simple +from werkzeug.serving import is_running_from_reloader +from werkzeug.utils import import_string + +from .globals import current_app +from .helpers import get_debug_flag +from .helpers import get_load_dotenv + +if t.TYPE_CHECKING: + from .app import Flask + + +class NoAppException(click.UsageError): + """Raised if an application cannot be found or loaded.""" + + +def find_best_app(module): + """Given a module instance this tries to find the best possible + application in the module or raises an exception. + """ + from . import Flask + + # Search for the most common names first. + for attr_name in ("app", "application"): + app = getattr(module, attr_name, None) + + if isinstance(app, Flask): + return app + + # Otherwise find the only object that is a Flask instance. + matches = [v for v in module.__dict__.values() if isinstance(v, Flask)] + + if len(matches) == 1: + return matches[0] + elif len(matches) > 1: + raise NoAppException( + "Detected multiple Flask applications in module" + f" '{module.__name__}'. Use '{module.__name__}:name'" + " to specify the correct one." + ) + + # Search for app factory functions. + for attr_name in ("create_app", "make_app"): + app_factory = getattr(module, attr_name, None) + + if inspect.isfunction(app_factory): + try: + app = app_factory() + + if isinstance(app, Flask): + return app + except TypeError as e: + if not _called_with_wrong_args(app_factory): + raise + + raise NoAppException( + f"Detected factory '{attr_name}' in module '{module.__name__}'," + " but could not call it without arguments. Use" + f" '{module.__name__}:{attr_name}(args)'" + " to specify arguments." + ) from e + + raise NoAppException( + "Failed to find Flask application or factory in module" + f" '{module.__name__}'. Use '{module.__name__}:name'" + " to specify one." + ) + + +def _called_with_wrong_args(f): + """Check whether calling a function raised a ``TypeError`` because + the call failed or because something in the factory raised the + error. + + :param f: The function that was called. + :return: ``True`` if the call failed. + """ + tb = sys.exc_info()[2] + + try: + while tb is not None: + if tb.tb_frame.f_code is f.__code__: + # In the function, it was called successfully. + return False + + tb = tb.tb_next + + # Didn't reach the function. + return True + finally: + # Delete tb to break a circular reference. + # https://docs.python.org/2/library/sys.html#sys.exc_info + del tb + + +def find_app_by_string(module, app_name): + """Check if the given string is a variable name or a function. Call + a function to get the app instance, or return the variable directly. + """ + from . import Flask + + # Parse app_name as a single expression to determine if it's a valid + # attribute name or function call. + try: + expr = ast.parse(app_name.strip(), mode="eval").body + except SyntaxError: + raise NoAppException( + f"Failed to parse {app_name!r} as an attribute name or function call." + ) from None + + if isinstance(expr, ast.Name): + name = expr.id + args = [] + kwargs = {} + elif isinstance(expr, ast.Call): + # Ensure the function name is an attribute name only. + if not isinstance(expr.func, ast.Name): + raise NoAppException( + f"Function reference must be a simple name: {app_name!r}." + ) + + name = expr.func.id + + # Parse the positional and keyword arguments as literals. + try: + args = [ast.literal_eval(arg) for arg in expr.args] + kwargs = {kw.arg: ast.literal_eval(kw.value) for kw in expr.keywords} + except ValueError: + # literal_eval gives cryptic error messages, show a generic + # message with the full expression instead. + raise NoAppException( + f"Failed to parse arguments as literal values: {app_name!r}." + ) from None + else: + raise NoAppException( + f"Failed to parse {app_name!r} as an attribute name or function call." + ) + + try: + attr = getattr(module, name) + except AttributeError as e: + raise NoAppException( + f"Failed to find attribute {name!r} in {module.__name__!r}." + ) from e + + # If the attribute is a function, call it with any args and kwargs + # to get the real application. + if inspect.isfunction(attr): + try: + app = attr(*args, **kwargs) + except TypeError as e: + if not _called_with_wrong_args(attr): + raise + + raise NoAppException( + f"The factory {app_name!r} in module" + f" {module.__name__!r} could not be called with the" + " specified arguments." + ) from e + else: + app = attr + + if isinstance(app, Flask): + return app + + raise NoAppException( + "A valid Flask application was not obtained from" + f" '{module.__name__}:{app_name}'." + ) + + +def prepare_import(path): + """Given a filename this will try to calculate the python path, add it + to the search path and return the actual module name that is expected. + """ + path = os.path.realpath(path) + + fname, ext = os.path.splitext(path) + if ext == ".py": + path = fname + + if os.path.basename(path) == "__init__": + path = os.path.dirname(path) + + module_name = [] + + # move up until outside package structure (no __init__.py) + while True: + path, name = os.path.split(path) + module_name.append(name) + + if not os.path.exists(os.path.join(path, "__init__.py")): + break + + if sys.path[0] != path: + sys.path.insert(0, path) + + return ".".join(module_name[::-1]) + + +def locate_app(module_name, app_name, raise_if_not_found=True): + try: + __import__(module_name) + except ImportError: + # Reraise the ImportError if it occurred within the imported module. + # Determine this by checking whether the trace has a depth > 1. + if sys.exc_info()[2].tb_next: + raise NoAppException( + f"While importing {module_name!r}, an ImportError was" + f" raised:\n\n{traceback.format_exc()}" + ) from None + elif raise_if_not_found: + raise NoAppException(f"Could not import {module_name!r}.") from None + else: + return + + module = sys.modules[module_name] + + if app_name is None: + return find_best_app(module) + else: + return find_app_by_string(module, app_name) + + +def get_version(ctx, param, value): + if not value or ctx.resilient_parsing: + return + + import werkzeug + from . import __version__ + + click.echo( + f"Python {platform.python_version()}\n" + f"Flask {__version__}\n" + f"Werkzeug {werkzeug.__version__}", + color=ctx.color, + ) + ctx.exit() + + +version_option = click.Option( + ["--version"], + help="Show the Flask version.", + expose_value=False, + callback=get_version, + is_flag=True, + is_eager=True, +) + + +class ScriptInfo: + """Helper object to deal with Flask applications. This is usually not + necessary to interface with as it's used internally in the dispatching + to click. In future versions of Flask this object will most likely play + a bigger role. Typically it's created automatically by the + :class:`FlaskGroup` but you can also manually create it and pass it + onwards as click object. + """ + + def __init__( + self, + app_import_path: str | None = None, + create_app: t.Callable[..., Flask] | None = None, + set_debug_flag: bool = True, + ) -> None: + #: Optionally the import path for the Flask application. + self.app_import_path = app_import_path + #: Optionally a function that is passed the script info to create + #: the instance of the application. + self.create_app = create_app + #: A dictionary with arbitrary data that can be associated with + #: this script info. + self.data: dict[t.Any, t.Any] = {} + self.set_debug_flag = set_debug_flag + self._loaded_app: Flask | None = None + + def load_app(self) -> Flask: + """Loads the Flask app (if not yet loaded) and returns it. Calling + this multiple times will just result in the already loaded app to + be returned. + """ + if self._loaded_app is not None: + return self._loaded_app + + if self.create_app is not None: + app = self.create_app() + else: + if self.app_import_path: + path, name = ( + re.split(r":(?![\\/])", self.app_import_path, 1) + [None] + )[:2] + import_name = prepare_import(path) + app = locate_app(import_name, name) + else: + for path in ("wsgi.py", "app.py"): + import_name = prepare_import(path) + app = locate_app(import_name, None, raise_if_not_found=False) + + if app: + break + + if not app: + raise NoAppException( + "Could not locate a Flask application. Use the" + " 'flask --app' option, 'FLASK_APP' environment" + " variable, or a 'wsgi.py' or 'app.py' file in the" + " current directory." + ) + + if self.set_debug_flag: + # Update the app's debug flag through the descriptor so that + # other values repopulate as well. + app.debug = get_debug_flag() + + self._loaded_app = app + return app + + +pass_script_info = click.make_pass_decorator(ScriptInfo, ensure=True) + + +def with_appcontext(f): + """Wraps a callback so that it's guaranteed to be executed with the + script's application context. + + Custom commands (and their options) registered under ``app.cli`` or + ``blueprint.cli`` will always have an app context available, this + decorator is not required in that case. + + .. versionchanged:: 2.2 + The app context is active for subcommands as well as the + decorated callback. The app context is always available to + ``app.cli`` command and parameter callbacks. + """ + + @click.pass_context + def decorator(__ctx, *args, **kwargs): + if not current_app: + app = __ctx.ensure_object(ScriptInfo).load_app() + __ctx.with_resource(app.app_context()) + + return __ctx.invoke(f, *args, **kwargs) + + return update_wrapper(decorator, f) + + +class AppGroup(click.Group): + """This works similar to a regular click :class:`~click.Group` but it + changes the behavior of the :meth:`command` decorator so that it + automatically wraps the functions in :func:`with_appcontext`. + + Not to be confused with :class:`FlaskGroup`. + """ + + def command(self, *args, **kwargs): + """This works exactly like the method of the same name on a regular + :class:`click.Group` but it wraps callbacks in :func:`with_appcontext` + unless it's disabled by passing ``with_appcontext=False``. + """ + wrap_for_ctx = kwargs.pop("with_appcontext", True) + + def decorator(f): + if wrap_for_ctx: + f = with_appcontext(f) + return click.Group.command(self, *args, **kwargs)(f) + + return decorator + + def group(self, *args, **kwargs): + """This works exactly like the method of the same name on a regular + :class:`click.Group` but it defaults the group class to + :class:`AppGroup`. + """ + kwargs.setdefault("cls", AppGroup) + return click.Group.group(self, *args, **kwargs) + + +def _set_app(ctx: click.Context, param: click.Option, value: str | None) -> str | None: + if value is None: + return None + + info = ctx.ensure_object(ScriptInfo) + info.app_import_path = value + return value + + +# This option is eager so the app will be available if --help is given. +# --help is also eager, so --app must be before it in the param list. +# no_args_is_help bypasses eager processing, so this option must be +# processed manually in that case to ensure FLASK_APP gets picked up. +_app_option = click.Option( + ["-A", "--app"], + metavar="IMPORT", + help=( + "The Flask application or factory function to load, in the form 'module:name'." + " Module can be a dotted import or file path. Name is not required if it is" + " 'app', 'application', 'create_app', or 'make_app', and can be 'name(args)' to" + " pass arguments." + ), + is_eager=True, + expose_value=False, + callback=_set_app, +) + + +def _set_debug(ctx: click.Context, param: click.Option, value: bool) -> bool | None: + # If the flag isn't provided, it will default to False. Don't use + # that, let debug be set by env in that case. + source = ctx.get_parameter_source(param.name) # type: ignore[arg-type] + + if source is not None and source in ( + ParameterSource.DEFAULT, + ParameterSource.DEFAULT_MAP, + ): + return None + + # Set with env var instead of ScriptInfo.load so that it can be + # accessed early during a factory function. + os.environ["FLASK_DEBUG"] = "1" if value else "0" + return value + + +_debug_option = click.Option( + ["--debug/--no-debug"], + help="Set debug mode.", + expose_value=False, + callback=_set_debug, +) + + +def _env_file_callback( + ctx: click.Context, param: click.Option, value: str | None +) -> str | None: + if value is None: + return None + + import importlib + + try: + importlib.import_module("dotenv") + except ImportError: + raise click.BadParameter( + "python-dotenv must be installed to load an env file.", + ctx=ctx, + param=param, + ) from None + + # Don't check FLASK_SKIP_DOTENV, that only disables automatically + # loading .env and .flaskenv files. + load_dotenv(value) + return value + + +# This option is eager so env vars are loaded as early as possible to be +# used by other options. +_env_file_option = click.Option( + ["-e", "--env-file"], + type=click.Path(exists=True, dir_okay=False), + help="Load environment variables from this file. python-dotenv must be installed.", + is_eager=True, + expose_value=False, + callback=_env_file_callback, +) + + +class FlaskGroup(AppGroup): + """Special subclass of the :class:`AppGroup` group that supports + loading more commands from the configured Flask app. Normally a + developer does not have to interface with this class but there are + some very advanced use cases for which it makes sense to create an + instance of this. see :ref:`custom-scripts`. + + :param add_default_commands: if this is True then the default run and + shell commands will be added. + :param add_version_option: adds the ``--version`` option. + :param create_app: an optional callback that is passed the script info and + returns the loaded app. + :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv` + files to set environment variables. Will also change the working + directory to the directory containing the first file found. + :param set_debug_flag: Set the app's debug flag. + + .. versionchanged:: 2.2 + Added the ``-A/--app``, ``--debug/--no-debug``, ``-e/--env-file`` options. + + .. versionchanged:: 2.2 + An app context is pushed when running ``app.cli`` commands, so + ``@with_appcontext`` is no longer required for those commands. + + .. versionchanged:: 1.0 + If installed, python-dotenv will be used to load environment variables + from :file:`.env` and :file:`.flaskenv` files. + """ + + def __init__( + self, + add_default_commands: bool = True, + create_app: t.Callable[..., Flask] | None = None, + add_version_option: bool = True, + load_dotenv: bool = True, + set_debug_flag: bool = True, + **extra: t.Any, + ) -> None: + params = list(extra.pop("params", None) or ()) + # Processing is done with option callbacks instead of a group + # callback. This allows users to make a custom group callback + # without losing the behavior. --env-file must come first so + # that it is eagerly evaluated before --app. + params.extend((_env_file_option, _app_option, _debug_option)) + + if add_version_option: + params.append(version_option) + + if "context_settings" not in extra: + extra["context_settings"] = {} + + extra["context_settings"].setdefault("auto_envvar_prefix", "FLASK") + + super().__init__(params=params, **extra) + + self.create_app = create_app + self.load_dotenv = load_dotenv + self.set_debug_flag = set_debug_flag + + if add_default_commands: + self.add_command(run_command) + self.add_command(shell_command) + self.add_command(routes_command) + + self._loaded_plugin_commands = False + + def _load_plugin_commands(self): + if self._loaded_plugin_commands: + return + + if sys.version_info >= (3, 10): + from importlib import metadata + else: + # Use a backport on Python < 3.10. We technically have + # importlib.metadata on 3.8+, but the API changed in 3.10, + # so use the backport for consistency. + import importlib_metadata as metadata + + for ep in metadata.entry_points(group="flask.commands"): + self.add_command(ep.load(), ep.name) + + self._loaded_plugin_commands = True + + def get_command(self, ctx, name): + self._load_plugin_commands() + # Look up built-in and plugin commands, which should be + # available even if the app fails to load. + rv = super().get_command(ctx, name) + + if rv is not None: + return rv + + info = ctx.ensure_object(ScriptInfo) + + # Look up commands provided by the app, showing an error and + # continuing if the app couldn't be loaded. + try: + app = info.load_app() + except NoAppException as e: + click.secho(f"Error: {e.format_message()}\n", err=True, fg="red") + return None + + # Push an app context for the loaded app unless it is already + # active somehow. This makes the context available to parameter + # and command callbacks without needing @with_appcontext. + if not current_app or current_app._get_current_object() is not app: + ctx.with_resource(app.app_context()) + + return app.cli.get_command(ctx, name) + + def list_commands(self, ctx): + self._load_plugin_commands() + # Start with the built-in and plugin commands. + rv = set(super().list_commands(ctx)) + info = ctx.ensure_object(ScriptInfo) + + # Add commands provided by the app, showing an error and + # continuing if the app couldn't be loaded. + try: + rv.update(info.load_app().cli.list_commands(ctx)) + except NoAppException as e: + # When an app couldn't be loaded, show the error message + # without the traceback. + click.secho(f"Error: {e.format_message()}\n", err=True, fg="red") + except Exception: + # When any other errors occurred during loading, show the + # full traceback. + click.secho(f"{traceback.format_exc()}\n", err=True, fg="red") + + return sorted(rv) + + def make_context( + self, + info_name: str | None, + args: list[str], + parent: click.Context | None = None, + **extra: t.Any, + ) -> click.Context: + # Set a flag to tell app.run to become a no-op. If app.run was + # not in a __name__ == __main__ guard, it would start the server + # when importing, blocking whatever command is being called. + os.environ["FLASK_RUN_FROM_CLI"] = "true" + + # Attempt to load .env and .flask env files. The --env-file + # option can cause another file to be loaded. + if get_load_dotenv(self.load_dotenv): + load_dotenv() + + if "obj" not in extra and "obj" not in self.context_settings: + extra["obj"] = ScriptInfo( + create_app=self.create_app, set_debug_flag=self.set_debug_flag + ) + + return super().make_context(info_name, args, parent=parent, **extra) + + def parse_args(self, ctx: click.Context, args: list[str]) -> list[str]: + if not args and self.no_args_is_help: + # Attempt to load --env-file and --app early in case they + # were given as env vars. Otherwise no_args_is_help will not + # see commands from app.cli. + _env_file_option.handle_parse_result(ctx, {}, []) + _app_option.handle_parse_result(ctx, {}, []) + + return super().parse_args(ctx, args) + + +def _path_is_ancestor(path, other): + """Take ``other`` and remove the length of ``path`` from it. Then join it + to ``path``. If it is the original value, ``path`` is an ancestor of + ``other``.""" + return os.path.join(path, other[len(path) :].lstrip(os.sep)) == other + + +def load_dotenv(path: str | os.PathLike | None = None) -> bool: + """Load "dotenv" files in order of precedence to set environment variables. + + If an env var is already set it is not overwritten, so earlier files in the + list are preferred over later files. + + This is a no-op if `python-dotenv`_ is not installed. + + .. _python-dotenv: https://github.com/theskumar/python-dotenv#readme + + :param path: Load the file at this location instead of searching. + :return: ``True`` if a file was loaded. + + .. versionchanged:: 2.0 + The current directory is not changed to the location of the + loaded file. + + .. versionchanged:: 2.0 + When loading the env files, set the default encoding to UTF-8. + + .. versionchanged:: 1.1.0 + Returns ``False`` when python-dotenv is not installed, or when + the given path isn't a file. + + .. versionadded:: 1.0 + """ + try: + import dotenv + except ImportError: + if path or os.path.isfile(".env") or os.path.isfile(".flaskenv"): + click.secho( + " * Tip: There are .env or .flaskenv files present." + ' Do "pip install python-dotenv" to use them.', + fg="yellow", + err=True, + ) + + return False + + # Always return after attempting to load a given path, don't load + # the default files. + if path is not None: + if os.path.isfile(path): + return dotenv.load_dotenv(path, encoding="utf-8") + + return False + + loaded = False + + for name in (".env", ".flaskenv"): + path = dotenv.find_dotenv(name, usecwd=True) + + if not path: + continue + + dotenv.load_dotenv(path, encoding="utf-8") + loaded = True + + return loaded # True if at least one file was located and loaded. + + +def show_server_banner(debug, app_import_path): + """Show extra startup messages the first time the server is run, + ignoring the reloader. + """ + if is_running_from_reloader(): + return + + if app_import_path is not None: + click.echo(f" * Serving Flask app '{app_import_path}'") + + if debug is not None: + click.echo(f" * Debug mode: {'on' if debug else 'off'}") + + +class CertParamType(click.ParamType): + """Click option type for the ``--cert`` option. Allows either an + existing file, the string ``'adhoc'``, or an import for a + :class:`~ssl.SSLContext` object. + """ + + name = "path" + + def __init__(self): + self.path_type = click.Path(exists=True, dir_okay=False, resolve_path=True) + + def convert(self, value, param, ctx): + try: + import ssl + except ImportError: + raise click.BadParameter( + 'Using "--cert" requires Python to be compiled with SSL support.', + ctx, + param, + ) from None + + try: + return self.path_type(value, param, ctx) + except click.BadParameter: + value = click.STRING(value, param, ctx).lower() + + if value == "adhoc": + try: + import cryptography # noqa: F401 + except ImportError: + raise click.BadParameter( + "Using ad-hoc certificates requires the cryptography library.", + ctx, + param, + ) from None + + return value + + obj = import_string(value, silent=True) + + if isinstance(obj, ssl.SSLContext): + return obj + + raise + + +def _validate_key(ctx, param, value): + """The ``--key`` option must be specified when ``--cert`` is a file. + Modifies the ``cert`` param to be a ``(cert, key)`` pair if needed. + """ + cert = ctx.params.get("cert") + is_adhoc = cert == "adhoc" + + try: + import ssl + except ImportError: + is_context = False + else: + is_context = isinstance(cert, ssl.SSLContext) + + if value is not None: + if is_adhoc: + raise click.BadParameter( + 'When "--cert" is "adhoc", "--key" is not used.', ctx, param + ) + + if is_context: + raise click.BadParameter( + 'When "--cert" is an SSLContext object, "--key is not used.', ctx, param + ) + + if not cert: + raise click.BadParameter('"--cert" must also be specified.', ctx, param) + + ctx.params["cert"] = cert, value + + else: + if cert and not (is_adhoc or is_context): + raise click.BadParameter('Required when using "--cert".', ctx, param) + + return value + + +class SeparatedPathType(click.Path): + """Click option type that accepts a list of values separated by the + OS's path separator (``:``, ``;`` on Windows). Each value is + validated as a :class:`click.Path` type. + """ + + def convert(self, value, param, ctx): + items = self.split_envvar_value(value) + super_convert = super().convert + return [super_convert(item, param, ctx) for item in items] + + +@click.command("run", short_help="Run a development server.") +@click.option("--host", "-h", default="127.0.0.1", help="The interface to bind to.") +@click.option("--port", "-p", default=5000, help="The port to bind to.") +@click.option( + "--cert", + type=CertParamType(), + help="Specify a certificate file to use HTTPS.", + is_eager=True, +) +@click.option( + "--key", + type=click.Path(exists=True, dir_okay=False, resolve_path=True), + callback=_validate_key, + expose_value=False, + help="The key file to use when specifying a certificate.", +) +@click.option( + "--reload/--no-reload", + default=None, + help="Enable or disable the reloader. By default the reloader " + "is active if debug is enabled.", +) +@click.option( + "--debugger/--no-debugger", + default=None, + help="Enable or disable the debugger. By default the debugger " + "is active if debug is enabled.", +) +@click.option( + "--with-threads/--without-threads", + default=True, + help="Enable or disable multithreading.", +) +@click.option( + "--extra-files", + default=None, + type=SeparatedPathType(), + help=( + "Extra files that trigger a reload on change. Multiple paths" + f" are separated by {os.path.pathsep!r}." + ), +) +@click.option( + "--exclude-patterns", + default=None, + type=SeparatedPathType(), + help=( + "Files matching these fnmatch patterns will not trigger a reload" + " on change. Multiple patterns are separated by" + f" {os.path.pathsep!r}." + ), +) +@pass_script_info +def run_command( + info, + host, + port, + reload, + debugger, + with_threads, + cert, + extra_files, + exclude_patterns, +): + """Run a local development server. + + This server is for development purposes only. It does not provide + the stability, security, or performance of production WSGI servers. + + The reloader and debugger are enabled by default with the '--debug' + option. + """ + try: + app = info.load_app() + except Exception as e: + if is_running_from_reloader(): + # When reloading, print out the error immediately, but raise + # it later so the debugger or server can handle it. + traceback.print_exc() + err = e + + def app(environ, start_response): + raise err from None + + else: + # When not reloading, raise the error immediately so the + # command fails. + raise e from None + + debug = get_debug_flag() + + if reload is None: + reload = debug + + if debugger is None: + debugger = debug + + show_server_banner(debug, info.app_import_path) + + run_simple( + host, + port, + app, + use_reloader=reload, + use_debugger=debugger, + threaded=with_threads, + ssl_context=cert, + extra_files=extra_files, + exclude_patterns=exclude_patterns, + ) + + +run_command.params.insert(0, _debug_option) + + +@click.command("shell", short_help="Run a shell in the app context.") +@with_appcontext +def shell_command() -> None: + """Run an interactive Python shell in the context of a given + Flask application. The application will populate the default + namespace of this shell according to its configuration. + + This is useful for executing small snippets of management code + without having to manually configure the application. + """ + import code + + banner = ( + f"Python {sys.version} on {sys.platform}\n" + f"App: {current_app.import_name}\n" + f"Instance: {current_app.instance_path}" + ) + ctx: dict = {} + + # Support the regular Python interpreter startup script if someone + # is using it. + startup = os.environ.get("PYTHONSTARTUP") + if startup and os.path.isfile(startup): + with open(startup) as f: + eval(compile(f.read(), startup, "exec"), ctx) + + ctx.update(current_app.make_shell_context()) + + # Site, customize, or startup script can set a hook to call when + # entering interactive mode. The default one sets up readline with + # tab and history completion. + interactive_hook = getattr(sys, "__interactivehook__", None) + + if interactive_hook is not None: + try: + import readline + from rlcompleter import Completer + except ImportError: + pass + else: + # rlcompleter uses __main__.__dict__ by default, which is + # flask.__main__. Use the shell context instead. + readline.set_completer(Completer(ctx).complete) + + interactive_hook() + + code.interact(banner=banner, local=ctx) + + +@click.command("routes", short_help="Show the routes for the app.") +@click.option( + "--sort", + "-s", + type=click.Choice(("endpoint", "methods", "domain", "rule", "match")), + default="endpoint", + help=( + "Method to sort routes by. 'match' is the order that Flask will match routes" + " when dispatching a request." + ), +) +@click.option("--all-methods", is_flag=True, help="Show HEAD and OPTIONS methods.") +@with_appcontext +def routes_command(sort: str, all_methods: bool) -> None: + """Show all registered routes with endpoints and methods.""" + rules = list(current_app.url_map.iter_rules()) + + if not rules: + click.echo("No routes were registered.") + return + + ignored_methods = set() if all_methods else {"HEAD", "OPTIONS"} + host_matching = current_app.url_map.host_matching + has_domain = any(rule.host if host_matching else rule.subdomain for rule in rules) + rows = [] + + for rule in rules: + row = [ + rule.endpoint, + ", ".join(sorted((rule.methods or set()) - ignored_methods)), + ] + + if has_domain: + row.append((rule.host if host_matching else rule.subdomain) or "") + + row.append(rule.rule) + rows.append(row) + + headers = ["Endpoint", "Methods"] + sorts = ["endpoint", "methods"] + + if has_domain: + headers.append("Host" if host_matching else "Subdomain") + sorts.append("domain") + + headers.append("Rule") + sorts.append("rule") + + try: + rows.sort(key=itemgetter(sorts.index(sort))) + except ValueError: + pass + + rows.insert(0, headers) + widths = [max(len(row[i]) for row in rows) for i in range(len(headers))] + rows.insert(1, ["-" * w for w in widths]) + template = " ".join(f"{{{i}:<{w}}}" for i, w in enumerate(widths)) + + for row in rows: + click.echo(template.format(*row)) + + +cli = FlaskGroup( + name="flask", + help="""\ +A general utility script for Flask applications. + +An application to load must be given with the '--app' option, +'FLASK_APP' environment variable, or with a 'wsgi.py' or 'app.py' file +in the current directory. +""", +) + + +def main() -> None: + cli.main() + + +if __name__ == "__main__": + main() diff --git a/.venv/Lib/site-packages/flask/config.py b/.venv/Lib/site-packages/flask/config.py new file mode 100644 index 000000000..a73dd786b --- /dev/null +++ b/.venv/Lib/site-packages/flask/config.py @@ -0,0 +1,345 @@ +from __future__ import annotations + +import errno +import json +import os +import types +import typing as t + +from werkzeug.utils import import_string + + +class ConfigAttribute: + """Makes an attribute forward to the config""" + + def __init__(self, name: str, get_converter: t.Callable | None = 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: dict | None = None) -> None: + super().__init__(defaults or {}) + self.root_path = root_path + + def from_envvar(self, variable_name: str, silent: bool = False) -> bool: + """Loads a configuration from an environment variable pointing to + a configuration file. This is basically just a shortcut with nicer + error messages for this line of code:: + + app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS']) + + :param variable_name: name of the environment variable + :param silent: set to ``True`` if you want silent failure for missing + files. + :return: ``True`` if the file was loaded successfully. + """ + rv = os.environ.get(variable_name) + if not rv: + if silent: + return False + raise RuntimeError( + f"The environment variable {variable_name!r} is not set" + " and as such configuration could not be loaded. Set" + " this variable and make it point to a configuration" + " file" + ) + return self.from_pyfile(rv, silent=silent) + + def from_prefixed_env( + self, prefix: str = "FLASK", *, loads: t.Callable[[str], t.Any] = json.loads + ) -> bool: + """Load any environment variables that start with ``FLASK_``, + dropping the prefix from the env key for the config key. Values + are passed through a loading function to attempt to convert them + to more specific types than strings. + + Keys are loaded in :func:`sorted` order. + + The default loading function attempts to parse values as any + valid JSON type, including dicts and lists. + + Specific items in nested dicts can be set by separating the + keys with double underscores (``__``). If an intermediate key + doesn't exist, it will be initialized to an empty dict. + + :param prefix: Load env vars that start with this prefix, + separated with an underscore (``_``). + :param loads: Pass each string value to this function and use + the returned value as the config value. If any error is + raised it is ignored and the value remains a string. The + default is :func:`json.loads`. + + .. versionadded:: 2.1 + """ + prefix = f"{prefix}_" + len_prefix = len(prefix) + + for key in sorted(os.environ): + if not key.startswith(prefix): + continue + + value = os.environ[key] + + try: + value = loads(value) + except Exception: + # Keep the value as a string if loading failed. + pass + + # Change to key.removeprefix(prefix) on Python >= 3.9. + key = key[len_prefix:] + + if "__" not in key: + # A non-nested key, set directly. + self[key] = value + continue + + # Traverse nested dictionaries with keys separated by "__". + current = self + *parts, tail = key.split("__") + + for part in parts: + # If an intermediate dict does not exist, create it. + if part not in current: + current[part] = {} + + current = current[part] + + current[tail] = value + + return True + + def from_pyfile(self, filename: str, silent: bool = False) -> bool: + """Updates the values in the config from a Python file. This function + behaves as if the file was imported as module with the + :meth:`from_object` function. + + :param filename: the filename of the config. This can either be an + absolute filename or a filename relative to the + root path. + :param silent: set to ``True`` if you want silent failure for missing + files. + :return: ``True`` if the file was loaded successfully. + + .. versionadded:: 0.7 + `silent` parameter. + """ + filename = os.path.join(self.root_path, filename) + d = types.ModuleType("config") + d.__file__ = filename + try: + with open(filename, mode="rb") as config_file: + exec(compile(config_file.read(), filename, "exec"), d.__dict__) + except OSError as e: + if silent and e.errno in (errno.ENOENT, errno.EISDIR, errno.ENOTDIR): + return False + e.strerror = f"Unable to load configuration file ({e.strerror})" + raise + self.from_object(d) + return True + + def from_object(self, obj: object | str) -> None: + """Updates the values from the given object. An object can be of one + of the following two types: + + - a string: in this case the object with that name will be imported + - an actual object reference: that object is used directly + + Objects are usually either modules or classes. :meth:`from_object` + loads only the uppercase attributes of the module/class. A ``dict`` + object will not work with :meth:`from_object` because the keys of a + ``dict`` are not attributes of the ``dict`` class. + + Example of module-based configuration:: + + app.config.from_object('yourapplication.default_config') + from yourapplication import default_config + app.config.from_object(default_config) + + Nothing is done to the object before loading. If the object is a + class and has ``@property`` attributes, it needs to be + instantiated before being passed to this method. + + You should not use this function to load the actual configuration but + rather configuration defaults. The actual config should be loaded + with :meth:`from_pyfile` and ideally from a location not within the + package because the package might be installed system wide. + + See :ref:`config-dev-prod` for an example of class-based configuration + using :meth:`from_object`. + + :param obj: an import name or object + """ + if isinstance(obj, str): + obj = import_string(obj) + for key in dir(obj): + if key.isupper(): + self[key] = getattr(obj, key) + + def from_file( + self, + filename: str, + load: t.Callable[[t.IO[t.Any]], t.Mapping], + silent: bool = False, + text: bool = True, + ) -> bool: + """Update the values in the config from a file that is loaded + using the ``load`` parameter. The loaded data is passed to the + :meth:`from_mapping` method. + + .. code-block:: python + + import json + app.config.from_file("config.json", load=json.load) + + import tomllib + app.config.from_file("config.toml", load=tomllib.load, text=False) + + :param filename: The path to the data file. This can be an + absolute path or relative to the config root path. + :param load: A callable that takes a file handle and returns a + mapping of loaded data from the file. + :type load: ``Callable[[Reader], Mapping]`` where ``Reader`` + implements a ``read`` method. + :param silent: Ignore the file if it doesn't exist. + :param text: Open the file in text or binary mode. + :return: ``True`` if the file was loaded successfully. + + .. versionchanged:: 2.3 + The ``text`` parameter was added. + + .. versionadded:: 2.0 + """ + filename = os.path.join(self.root_path, filename) + + try: + with open(filename, "r" if text else "rb") as f: + obj = load(f) + except OSError as e: + if silent and e.errno in (errno.ENOENT, errno.EISDIR): + return False + + e.strerror = f"Unable to load configuration file ({e.strerror})" + raise + + return self.from_mapping(obj) + + def from_mapping( + self, mapping: t.Mapping[str, t.Any] | None = None, **kwargs: t.Any + ) -> bool: + """Updates the config like :meth:`update` ignoring items with + non-upper keys. + + :return: Always returns ``True``. + + .. versionadded:: 0.11 + """ + mappings: dict[str, t.Any] = {} + if mapping is not None: + mappings.update(mapping) + mappings.update(kwargs) + for key, value in mappings.items(): + if key.isupper(): + self[key] = value + return True + + def get_namespace( + self, namespace: str, lowercase: bool = True, trim_namespace: bool = True + ) -> dict[str, t.Any]: + """Returns a dictionary containing a subset of configuration options + that match the specified namespace/prefix. Example usage:: + + app.config['IMAGE_STORE_TYPE'] = 'fs' + app.config['IMAGE_STORE_PATH'] = '/var/app/images' + app.config['IMAGE_STORE_BASE_URL'] = 'http://img.website.com' + image_store_config = app.config.get_namespace('IMAGE_STORE_') + + The resulting dictionary `image_store_config` would look like:: + + { + 'type': 'fs', + 'path': '/var/app/images', + 'base_url': 'http://img.website.com' + } + + This is often useful when configuration options map directly to + keyword arguments in functions or class constructors. + + :param namespace: a configuration namespace + :param lowercase: a flag indicating if the keys of the resulting + dictionary should be lowercase + :param trim_namespace: a flag indicating if the keys of the resulting + dictionary should not include the namespace + + .. versionadded:: 0.11 + """ + rv = {} + for k, v in self.items(): + if not k.startswith(namespace): + continue + if trim_namespace: + key = k[len(namespace) :] + else: + key = k + if lowercase: + key = key.lower() + rv[key] = v + return rv + + def __repr__(self) -> str: + return f"<{type(self).__name__} {dict.__repr__(self)}>" diff --git a/.venv/Lib/site-packages/flask/ctx.py b/.venv/Lib/site-packages/flask/ctx.py new file mode 100644 index 000000000..b37e4e04a --- /dev/null +++ b/.venv/Lib/site-packages/flask/ctx.py @@ -0,0 +1,440 @@ +from __future__ import annotations + +import contextvars +import sys +import typing as t +from functools import update_wrapper +from types import TracebackType + +from werkzeug.exceptions import HTTPException + +from . import typing as ft +from .globals import _cv_app +from .globals import _cv_request +from .signals import appcontext_popped +from .signals import appcontext_pushed + +if t.TYPE_CHECKING: # pragma: no cover + from .app import Flask + from .sessions import SessionMixin + from .wrappers import Request + + +# a singleton sentinel value for parameter defaults +_sentinel = object() + + +class _AppCtxGlobals: + """A plain object. Used as a namespace for storing data during an + application context. + + Creating an app context automatically creates this object, which is + made available as the :data:`g` proxy. + + .. describe:: 'key' in g + + Check whether an attribute is present. + + .. versionadded:: 0.10 + + .. describe:: iter(g) + + Return an iterator over the attribute names. + + .. versionadded:: 0.10 + """ + + # Define attr methods to let mypy know this is a namespace object + # that has arbitrary attributes. + + def __getattr__(self, name: str) -> t.Any: + try: + return self.__dict__[name] + except KeyError: + raise AttributeError(name) from None + + def __setattr__(self, name: str, value: t.Any) -> None: + self.__dict__[name] = value + + def __delattr__(self, name: str) -> None: + try: + del self.__dict__[name] + except KeyError: + raise AttributeError(name) from None + + def get(self, name: str, default: t.Any | None = None) -> t.Any: + """Get an attribute by name, or a default value. Like + :meth:`dict.get`. + + :param name: Name of attribute to get. + :param default: Value to return if the attribute is not present. + + .. versionadded:: 0.10 + """ + return self.__dict__.get(name, default) + + def pop(self, name: str, default: t.Any = _sentinel) -> t.Any: + """Get and remove an attribute by name. Like :meth:`dict.pop`. + + :param name: Name of attribute to pop. + :param default: Value to return if the attribute is not present, + instead of raising a ``KeyError``. + + .. versionadded:: 0.11 + """ + if default is _sentinel: + return self.__dict__.pop(name) + else: + return self.__dict__.pop(name, default) + + def setdefault(self, name: str, default: t.Any = None) -> t.Any: + """Get the value of an attribute if it is present, otherwise + set and return a default value. Like :meth:`dict.setdefault`. + + :param name: Name of attribute to get. + :param default: Value to set and return if the attribute is not + present. + + .. versionadded:: 0.11 + """ + return self.__dict__.setdefault(name, default) + + def __contains__(self, item: str) -> bool: + return item in self.__dict__ + + def __iter__(self) -> t.Iterator[str]: + return iter(self.__dict__) + + def __repr__(self) -> str: + ctx = _cv_app.get(None) + if ctx is not None: + return f"" + return object.__repr__(self) + + +def after_this_request(f: ft.AfterRequestCallable) -> ft.AfterRequestCallable: + """Executes a function after this request. This is useful to modify + response objects. The function is passed the response object and has + to return the same or a new one. + + Example:: + + @app.route('/') + def index(): + @after_this_request + def add_header(response): + response.headers['X-Foo'] = 'Parachute' + return response + return 'Hello World!' + + This is more useful if a function other than the view function wants to + modify a response. For instance think of a decorator that wants to add + some headers without converting the return value into a response object. + + .. versionadded:: 0.9 + """ + ctx = _cv_request.get(None) + + if ctx is None: + raise RuntimeError( + "'after_this_request' can only be used when a request" + " context is active, such as in a view function." + ) + + ctx._after_request_functions.append(f) + return f + + +def copy_current_request_context(f: t.Callable) -> t.Callable: + """A helper function that decorates a function to retain the current + request context. This is useful when working with greenlets. The moment + the function is decorated a copy of the request context is created and + then pushed when the function is called. The current session is also + included in the copied request context. + + Example:: + + import gevent + from flask import copy_current_request_context + + @app.route('/') + def index(): + @copy_current_request_context + def do_some_work(): + # do some work here, it can access flask.request or + # flask.session like you would otherwise in the view function. + ... + gevent.spawn(do_some_work) + return 'Regular response' + + .. versionadded:: 0.10 + """ + ctx = _cv_request.get(None) + + if ctx is None: + raise RuntimeError( + "'copy_current_request_context' can only be used when a" + " request context is active, such as in a view function." + ) + + ctx = ctx.copy() + + def wrapper(*args, **kwargs): + with ctx: + return ctx.app.ensure_sync(f)(*args, **kwargs) + + return update_wrapper(wrapper, f) + + +def has_request_context() -> bool: + """If you have code that wants to test if a request context is there or + not this function can be used. For instance, you may want to take advantage + of request information if the request object is available, but fail + silently if it is unavailable. + + :: + + class User(db.Model): + + def __init__(self, username, remote_addr=None): + self.username = username + if remote_addr is None and has_request_context(): + remote_addr = request.remote_addr + self.remote_addr = remote_addr + + Alternatively you can also just test any of the context bound objects + (such as :class:`request` or :class:`g`) for truthness:: + + class User(db.Model): + + def __init__(self, username, remote_addr=None): + self.username = username + if remote_addr is None and request: + remote_addr = request.remote_addr + self.remote_addr = remote_addr + + .. versionadded:: 0.7 + """ + return _cv_request.get(None) is not None + + +def has_app_context() -> bool: + """Works like :func:`has_request_context` but for the application + context. You can also just do a boolean check on the + :data:`current_app` object instead. + + .. versionadded:: 0.9 + """ + return _cv_app.get(None) is not None + + +class AppContext: + """The app context contains application-specific information. An app + context is created and pushed at the beginning of each request if + one is not already active. An app context is also pushed when + running CLI commands. + """ + + def __init__(self, app: Flask) -> None: + self.app = app + self.url_adapter = app.create_url_adapter(None) + self.g: _AppCtxGlobals = app.app_ctx_globals_class() + self._cv_tokens: list[contextvars.Token] = [] + + def push(self) -> None: + """Binds the app context to the current context.""" + self._cv_tokens.append(_cv_app.set(self)) + appcontext_pushed.send(self.app, _async_wrapper=self.app.ensure_sync) + + def pop(self, exc: BaseException | None = _sentinel) -> None: # type: ignore + """Pops the app context.""" + try: + if len(self._cv_tokens) == 1: + if exc is _sentinel: + exc = sys.exc_info()[1] + self.app.do_teardown_appcontext(exc) + finally: + ctx = _cv_app.get() + _cv_app.reset(self._cv_tokens.pop()) + + if ctx is not self: + raise AssertionError( + f"Popped wrong app context. ({ctx!r} instead of {self!r})" + ) + + appcontext_popped.send(self.app, _async_wrapper=self.app.ensure_sync) + + def __enter__(self) -> AppContext: + self.push() + return self + + def __exit__( + self, + exc_type: type | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.pop(exc_value) + + +class RequestContext: + """The request context contains per-request information. The Flask + app creates and pushes it at the beginning of the request, then pops + it at the end of the request. It will create the URL adapter and + request object for the WSGI environment provided. + + Do not attempt to use this class directly, instead use + :meth:`~flask.Flask.test_request_context` and + :meth:`~flask.Flask.request_context` to create this object. + + When the request context is popped, it will evaluate all the + functions registered on the application for teardown execution + (:meth:`~flask.Flask.teardown_request`). + + The request context is automatically popped at the end of the + request. When using the interactive debugger, the context will be + restored so ``request`` is still accessible. Similarly, the test + client can preserve the context after the request ends. However, + teardown functions may already have closed some resources such as + database connections. + """ + + def __init__( + self, + app: Flask, + environ: dict, + request: Request | None = None, + session: SessionMixin | None = None, + ) -> None: + self.app = app + if request is None: + request = app.request_class(environ) + request.json_module = app.json + self.request: Request = request + self.url_adapter = None + try: + self.url_adapter = app.create_url_adapter(self.request) + except HTTPException as e: + self.request.routing_exception = e + self.flashes: list[tuple[str, str]] | None = None + self.session: SessionMixin | None = session + # Functions that should be executed after the request on the response + # object. These will be called before the regular "after_request" + # functions. + self._after_request_functions: list[ft.AfterRequestCallable] = [] + + self._cv_tokens: list[tuple[contextvars.Token, AppContext | None]] = [] + + def copy(self) -> RequestContext: + """Creates a copy of this request context with the same request object. + This can be used to move a request context to a different greenlet. + Because the actual request object is the same this cannot be used to + move a request context to a different thread unless access to the + request object is locked. + + .. versionadded:: 0.10 + + .. versionchanged:: 1.1 + The current session object is used instead of reloading the original + data. This prevents `flask.session` pointing to an out-of-date object. + """ + return self.__class__( + self.app, + environ=self.request.environ, + request=self.request, + session=self.session, + ) + + def match_request(self) -> None: + """Can be overridden by a subclass to hook into the matching + of the request. + """ + try: + result = self.url_adapter.match(return_rule=True) # type: ignore + self.request.url_rule, self.request.view_args = result # type: ignore + except HTTPException as e: + self.request.routing_exception = e + + def push(self) -> None: + # Before we push the request context we have to ensure that there + # is an application context. + app_ctx = _cv_app.get(None) + + if app_ctx is None or app_ctx.app is not self.app: + app_ctx = self.app.app_context() + app_ctx.push() + else: + app_ctx = None + + self._cv_tokens.append((_cv_request.set(self), app_ctx)) + + # Open the session at the moment that the request context is available. + # This allows a custom open_session method to use the request context. + # Only open a new session if this is the first time the request was + # pushed, otherwise stream_with_context loses the session. + if self.session is None: + session_interface = self.app.session_interface + self.session = session_interface.open_session(self.app, self.request) + + if self.session is None: + self.session = session_interface.make_null_session(self.app) + + # Match the request URL after loading the session, so that the + # session is available in custom URL converters. + if self.url_adapter is not None: + self.match_request() + + def pop(self, exc: BaseException | None = _sentinel) -> None: # type: ignore + """Pops the request context and unbinds it by doing that. This will + also trigger the execution of functions registered by the + :meth:`~flask.Flask.teardown_request` decorator. + + .. versionchanged:: 0.9 + Added the `exc` argument. + """ + clear_request = len(self._cv_tokens) == 1 + + try: + if clear_request: + if exc is _sentinel: + exc = sys.exc_info()[1] + self.app.do_teardown_request(exc) + + request_close = getattr(self.request, "close", None) + if request_close is not None: + request_close() + finally: + ctx = _cv_request.get() + token, app_ctx = self._cv_tokens.pop() + _cv_request.reset(token) + + # get rid of circular dependencies at the end of the request + # so that we don't require the GC to be active. + if clear_request: + ctx.request.environ["werkzeug.request"] = None + + if app_ctx is not None: + app_ctx.pop(exc) + + if ctx is not self: + raise AssertionError( + f"Popped wrong request context. ({ctx!r} instead of {self!r})" + ) + + def __enter__(self) -> RequestContext: + self.push() + return self + + def __exit__( + self, + exc_type: type | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.pop(exc_value) + + def __repr__(self) -> str: + return ( + f"<{type(self).__name__} {self.request.url!r}" + f" [{self.request.method}] of {self.app.name}>" + ) diff --git a/.venv/Lib/site-packages/flask/debughelpers.py b/.venv/Lib/site-packages/flask/debughelpers.py new file mode 100644 index 000000000..6061441a8 --- /dev/null +++ b/.venv/Lib/site-packages/flask/debughelpers.py @@ -0,0 +1,160 @@ +from __future__ import annotations + +import typing as t + +from .app import Flask +from .blueprints import Blueprint +from .globals import request_ctx + + +class UnexpectedUnicodeError(AssertionError, UnicodeError): + """Raised in places where we want some better error reporting for + unexpected unicode or binary data. + """ + + +class DebugFilesKeyError(KeyError, AssertionError): + """Raised from request.files during debugging. The idea is that it can + provide a better error message than just a generic KeyError/BadRequest. + """ + + def __init__(self, request, key): + form_matches = request.form.getlist(key) + buf = [ + f"You tried to access the file {key!r} in the request.files" + " dictionary but it does not exist. The mimetype for the" + f" request is {request.mimetype!r} instead of" + " 'multipart/form-data' which means that no file contents" + " were transmitted. To fix this error you should provide" + ' enctype="multipart/form-data" in your form.' + ] + if form_matches: + names = ", ".join(repr(x) for x in form_matches) + buf.append( + "\n\nThe browser instead transmitted some file names. " + f"This was submitted: {names}" + ) + self.msg = "".join(buf) + + def __str__(self): + return self.msg + + +class FormDataRoutingRedirect(AssertionError): + """This exception is raised in debug mode if a routing redirect + would cause the browser to drop the method or body. This happens + when method is not GET, HEAD or OPTIONS and the status code is not + 307 or 308. + """ + + def __init__(self, request): + exc = request.routing_exception + buf = [ + f"A request was sent to '{request.url}', but routing issued" + f" a redirect to the canonical URL '{exc.new_url}'." + ] + + if f"{request.base_url}/" == exc.new_url.partition("?")[0]: + buf.append( + " The URL was defined with a trailing slash. Flask" + " will redirect to the URL with a trailing slash if it" + " was accessed without one." + ) + + buf.append( + " Send requests to the canonical URL, or use 307 or 308 for" + " routing redirects. Otherwise, browsers will drop form" + " data.\n\n" + "This exception is only raised in debug mode." + ) + super().__init__("".join(buf)) + + +def attach_enctype_error_multidict(request): + """Patch ``request.files.__getitem__`` to raise a descriptive error + about ``enctype=multipart/form-data``. + + :param request: The request to patch. + :meta private: + """ + oldcls = request.files.__class__ + + class newcls(oldcls): + def __getitem__(self, key): + try: + return super().__getitem__(key) + except KeyError as e: + if key not in request.form: + raise + + raise DebugFilesKeyError(request, key).with_traceback( + e.__traceback__ + ) from None + + newcls.__name__ = oldcls.__name__ + newcls.__module__ = oldcls.__module__ + request.files.__class__ = newcls + + +def _dump_loader_info(loader) -> t.Generator: + yield f"class: {type(loader).__module__}.{type(loader).__name__}" + for key, value in sorted(loader.__dict__.items()): + if key.startswith("_"): + continue + if isinstance(value, (tuple, list)): + if not all(isinstance(x, str) for x in value): + continue + yield f"{key}:" + for item in value: + yield f" - {item}" + continue + elif not isinstance(value, (str, int, float, bool)): + continue + yield f"{key}: {value!r}" + + +def explain_template_loading_attempts(app: Flask, template, attempts) -> None: + """This should help developers understand what failed""" + info = [f"Locating template {template!r}:"] + total_found = 0 + blueprint = None + if request_ctx and request_ctx.request.blueprint is not None: + blueprint = request_ctx.request.blueprint + + for idx, (loader, srcobj, triple) in enumerate(attempts): + if isinstance(srcobj, Flask): + src_info = f"application {srcobj.import_name!r}" + elif isinstance(srcobj, Blueprint): + src_info = f"blueprint {srcobj.name!r} ({srcobj.import_name})" + else: + src_info = repr(srcobj) + + info.append(f"{idx + 1:5}: trying loader of {src_info}") + + for line in _dump_loader_info(loader): + info.append(f" {line}") + + if triple is None: + detail = "no match" + else: + detail = f"found ({triple[1] or ''!r})" + total_found += 1 + info.append(f" -> {detail}") + + seems_fishy = False + if total_found == 0: + info.append("Error: the template could not be found.") + seems_fishy = True + elif total_found > 1: + info.append("Warning: multiple loaders returned a match for the template.") + seems_fishy = True + + if blueprint is not None and seems_fishy: + info.append( + " The template was looked up from an endpoint that belongs" + f" to the blueprint {blueprint!r}." + ) + info.append(" Maybe you did not place a template in the right folder?") + info.append(" See https://flask.palletsprojects.com/blueprints/#templates") + + app.logger.info("\n".join(info)) diff --git a/.venv/Lib/site-packages/flask/globals.py b/.venv/Lib/site-packages/flask/globals.py new file mode 100644 index 000000000..e9cd4acfc --- /dev/null +++ b/.venv/Lib/site-packages/flask/globals.py @@ -0,0 +1,96 @@ +from __future__ import annotations + +import typing as t +from contextvars import ContextVar + +from werkzeug.local import LocalProxy + +if t.TYPE_CHECKING: # pragma: no cover + from .app import Flask + from .ctx import _AppCtxGlobals + from .ctx import AppContext + from .ctx import RequestContext + from .sessions import SessionMixin + from .wrappers import Request + + +class _FakeStack: + def __init__(self, name: str, cv: ContextVar[t.Any]) -> None: + self.name = name + self.cv = cv + + @property + def top(self) -> t.Any | None: + import warnings + + warnings.warn( + f"'_{self.name}_ctx_stack' is deprecated and will be removed in Flask 2.4." + f" Use 'g' to store data, or '{self.name}_ctx' to access the current" + " context.", + DeprecationWarning, + stacklevel=2, + ) + return self.cv.get(None) + + +_no_app_msg = """\ +Working outside of application context. + +This typically means that you attempted to use functionality that needed +the current application. To solve this, set up an application context +with app.app_context(). See the documentation for more information.\ +""" +_cv_app: ContextVar[AppContext] = ContextVar("flask.app_ctx") +__app_ctx_stack = _FakeStack("app", _cv_app) +app_ctx: AppContext = LocalProxy( # type: ignore[assignment] + _cv_app, unbound_message=_no_app_msg +) +current_app: Flask = LocalProxy( # type: ignore[assignment] + _cv_app, "app", unbound_message=_no_app_msg +) +g: _AppCtxGlobals = LocalProxy( # type: ignore[assignment] + _cv_app, "g", unbound_message=_no_app_msg +) + +_no_req_msg = """\ +Working outside of request context. + +This typically means that you attempted to use functionality that needed +an active HTTP request. Consult the documentation on testing for +information about how to avoid this problem.\ +""" +_cv_request: ContextVar[RequestContext] = ContextVar("flask.request_ctx") +__request_ctx_stack = _FakeStack("request", _cv_request) +request_ctx: RequestContext = LocalProxy( # type: ignore[assignment] + _cv_request, unbound_message=_no_req_msg +) +request: Request = LocalProxy( # type: ignore[assignment] + _cv_request, "request", unbound_message=_no_req_msg +) +session: SessionMixin = LocalProxy( # type: ignore[assignment] + _cv_request, "session", unbound_message=_no_req_msg +) + + +def __getattr__(name: str) -> t.Any: + if name == "_app_ctx_stack": + import warnings + + warnings.warn( + "'_app_ctx_stack' is deprecated and will be removed in Flask 2.4.", + DeprecationWarning, + stacklevel=2, + ) + return __app_ctx_stack + + if name == "_request_ctx_stack": + import warnings + + warnings.warn( + "'_request_ctx_stack' is deprecated and will be removed in Flask 2.4.", + DeprecationWarning, + stacklevel=2, + ) + return __request_ctx_stack + + raise AttributeError(name) diff --git a/.venv/Lib/site-packages/flask/helpers.py b/.venv/Lib/site-packages/flask/helpers.py new file mode 100644 index 000000000..61a0f818f --- /dev/null +++ b/.venv/Lib/site-packages/flask/helpers.py @@ -0,0 +1,693 @@ +from __future__ import annotations + +import os +import pkgutil +import socket +import sys +import typing as t +import warnings +from datetime import datetime +from functools import lru_cache +from functools import update_wrapper +from threading import RLock + +import werkzeug.utils +from werkzeug.exceptions import abort as _wz_abort +from werkzeug.utils import redirect as _wz_redirect + +from .globals import _cv_request +from .globals import current_app +from .globals import request +from .globals import request_ctx +from .globals import session +from .signals import message_flashed + +if t.TYPE_CHECKING: # pragma: no cover + from werkzeug.wrappers import Response as BaseResponse + from .wrappers import Response + + +def get_debug_flag() -> bool: + """Get whether debug mode should be enabled for the app, indicated by the + :envvar:`FLASK_DEBUG` environment variable. The default is ``False``. + """ + val = os.environ.get("FLASK_DEBUG") + return bool(val and val.lower() not in {"0", "false", "no"}) + + +def get_load_dotenv(default: bool = True) -> bool: + """Get whether the user has disabled loading default dotenv files by + setting :envvar:`FLASK_SKIP_DOTENV`. The default is ``True``, load + the files. + + :param default: What to return if the env var isn't set. + """ + val = os.environ.get("FLASK_SKIP_DOTENV") + + if not val: + return default + + return val.lower() in ("0", "false", "no") + + +def stream_with_context( + generator_or_function: ( + t.Iterator[t.AnyStr] | t.Callable[..., t.Iterator[t.AnyStr]] + ) +) -> t.Iterator[t.AnyStr]: + """Request contexts disappear when the response is started on the server. + This is done for efficiency reasons and to make it less likely to encounter + memory leaks with badly written WSGI middlewares. The downside is that if + you are using streamed responses, the generator cannot access request bound + information any more. + + This function however can help you keep the context around for longer:: + + from flask import stream_with_context, request, Response + + @app.route('/stream') + def streamed_response(): + @stream_with_context + def generate(): + yield 'Hello ' + yield request.args['name'] + yield '!' + return Response(generate()) + + Alternatively it can also be used around a specific generator:: + + from flask import stream_with_context, request, Response + + @app.route('/stream') + def streamed_response(): + def generate(): + yield 'Hello ' + yield request.args['name'] + yield '!' + return Response(stream_with_context(generate())) + + .. versionadded:: 0.9 + """ + try: + gen = iter(generator_or_function) # type: ignore + except TypeError: + + def decorator(*args: t.Any, **kwargs: t.Any) -> t.Any: + gen = generator_or_function(*args, **kwargs) # type: ignore + return stream_with_context(gen) + + return update_wrapper(decorator, generator_or_function) # type: ignore + + def generator() -> t.Generator: + ctx = _cv_request.get(None) + if ctx is None: + raise RuntimeError( + "'stream_with_context' can only be used when a request" + " context is active, such as in a view function." + ) + with ctx: + # Dummy sentinel. Has to be inside the context block or we're + # not actually keeping the context around. + yield None + + # The try/finally is here so that if someone passes a WSGI level + # iterator in we're still running the cleanup logic. Generators + # don't need that because they are closed on their destruction + # automatically. + try: + yield from gen + finally: + if hasattr(gen, "close"): + gen.close() + + # The trick is to start the generator. Then the code execution runs until + # the first dummy None is yielded at which point the context was already + # pushed. This item is discarded. Then when the iteration continues the + # real generator is executed. + wrapped_g = generator() + next(wrapped_g) + return wrapped_g + + +def make_response(*args: t.Any) -> Response: + """Sometimes it is necessary to set additional headers in a view. Because + views do not have to return response objects but can return a value that + is converted into a response object by Flask itself, it becomes tricky to + add headers to it. This function can be called instead of using a return + and you will get a response object which you can use to attach headers. + + If view looked like this and you want to add a new header:: + + def index(): + return render_template('index.html', foo=42) + + You can now do something like this:: + + def index(): + response = make_response(render_template('index.html', foo=42)) + response.headers['X-Parachutes'] = 'parachutes are cool' + return response + + This function accepts the very same arguments you can return from a + view function. This for example creates a response with a 404 error + code:: + + response = make_response(render_template('not_found.html'), 404) + + The other use case of this function is to force the return value of a + view function into a response which is helpful with view + decorators:: + + response = make_response(view_function()) + response.headers['X-Parachutes'] = 'parachutes are cool' + + Internally this function does the following things: + + - if no arguments are passed, it creates a new response argument + - if one argument is passed, :meth:`flask.Flask.make_response` + is invoked with it. + - if more than one argument is passed, the arguments are passed + to the :meth:`flask.Flask.make_response` function as tuple. + + .. versionadded:: 0.6 + """ + if not args: + return current_app.response_class() + if len(args) == 1: + args = args[0] + return current_app.make_response(args) # type: ignore + + +def url_for( + endpoint: str, + *, + _anchor: str | None = None, + _method: str | None = None, + _scheme: str | None = None, + _external: bool | None = None, + **values: t.Any, +) -> str: + """Generate a URL to the given endpoint with the given values. + + This requires an active request or application context, and calls + :meth:`current_app.url_for() `. See that method + for full documentation. + + :param endpoint: The endpoint name associated with the URL to + generate. If this starts with a ``.``, the current blueprint + name (if any) will be used. + :param _anchor: If given, append this as ``#anchor`` to the URL. + :param _method: If given, generate the URL associated with this + method for the endpoint. + :param _scheme: If given, the URL will have this scheme if it is + external. + :param _external: If given, prefer the URL to be internal (False) or + require it to be external (True). External URLs include the + scheme and domain. When not in an active request, URLs are + external by default. + :param values: Values to use for the variable parts of the URL rule. + Unknown keys are appended as query string arguments, like + ``?a=b&c=d``. + + .. versionchanged:: 2.2 + Calls ``current_app.url_for``, allowing an app to override the + behavior. + + .. versionchanged:: 0.10 + The ``_scheme`` parameter was added. + + .. versionchanged:: 0.9 + The ``_anchor`` and ``_method`` parameters were added. + + .. versionchanged:: 0.9 + Calls ``app.handle_url_build_error`` on build errors. + """ + return current_app.url_for( + endpoint, + _anchor=_anchor, + _method=_method, + _scheme=_scheme, + _external=_external, + **values, + ) + + +def redirect( + location: str, code: int = 302, Response: type[BaseResponse] | None = None +) -> BaseResponse: + """Create a redirect response object. + + If :data:`~flask.current_app` is available, it will use its + :meth:`~flask.Flask.redirect` method, otherwise it will use + :func:`werkzeug.utils.redirect`. + + :param location: The URL to redirect to. + :param code: The status code for the redirect. + :param Response: The response class to use. Not used when + ``current_app`` is active, which uses ``app.response_class``. + + .. versionadded:: 2.2 + Calls ``current_app.redirect`` if available instead of always + using Werkzeug's default ``redirect``. + """ + if current_app: + return current_app.redirect(location, code=code) + + return _wz_redirect(location, code=code, Response=Response) + + +def abort(code: int | BaseResponse, *args: t.Any, **kwargs: t.Any) -> t.NoReturn: + """Raise an :exc:`~werkzeug.exceptions.HTTPException` for the given + status code. + + If :data:`~flask.current_app` is available, it will call its + :attr:`~flask.Flask.aborter` object, otherwise it will use + :func:`werkzeug.exceptions.abort`. + + :param code: The status code for the exception, which must be + registered in ``app.aborter``. + :param args: Passed to the exception. + :param kwargs: Passed to the exception. + + .. versionadded:: 2.2 + Calls ``current_app.aborter`` if available instead of always + using Werkzeug's default ``abort``. + """ + if current_app: + current_app.aborter(code, *args, **kwargs) + + _wz_abort(code, *args, **kwargs) + + +def get_template_attribute(template_name: str, attribute: str) -> t.Any: + """Loads a macro (or variable) a template exports. This can be used to + invoke a macro from within Python code. If you for example have a + template named :file:`_cider.html` with the following contents: + + .. sourcecode:: html+jinja + + {% macro hello(name) %}Hello {{ name }}!{% endmacro %} + + You can access this from Python code like this:: + + hello = get_template_attribute('_cider.html', 'hello') + return hello('World') + + .. versionadded:: 0.2 + + :param template_name: the name of the template + :param attribute: the name of the variable of macro to access + """ + return getattr(current_app.jinja_env.get_template(template_name).module, attribute) + + +def flash(message: str, category: str = "message") -> None: + """Flashes a message to the next request. In order to remove the + flashed message from the session and to display it to the user, + the template has to call :func:`get_flashed_messages`. + + .. versionchanged:: 0.3 + `category` parameter added. + + :param message: the message to be flashed. + :param category: the category for the message. The following values + are recommended: ``'message'`` for any kind of message, + ``'error'`` for errors, ``'info'`` for information + messages and ``'warning'`` for warnings. However any + kind of string can be used as category. + """ + # Original implementation: + # + # session.setdefault('_flashes', []).append((category, message)) + # + # This assumed that changes made to mutable structures in the session are + # always in sync with the session object, which is not true for session + # implementations that use external storage for keeping their keys/values. + flashes = session.get("_flashes", []) + flashes.append((category, message)) + session["_flashes"] = flashes + app = current_app._get_current_object() # type: ignore + message_flashed.send( + app, + _async_wrapper=app.ensure_sync, + message=message, + category=category, + ) + + +def get_flashed_messages( + with_categories: bool = False, category_filter: t.Iterable[str] = () +) -> list[str] | list[tuple[str, str]]: + """Pulls all flashed messages from the session and returns them. + Further calls in the same request to the function will return + the same messages. By default just the messages are returned, + but when `with_categories` is set to ``True``, the return value will + be a list of tuples in the form ``(category, message)`` instead. + + Filter the flashed messages to one or more categories by providing those + categories in `category_filter`. This allows rendering categories in + separate html blocks. The `with_categories` and `category_filter` + arguments are distinct: + + * `with_categories` controls whether categories are returned with message + text (``True`` gives a tuple, where ``False`` gives just the message text). + * `category_filter` filters the messages down to only those matching the + provided categories. + + See :doc:`/patterns/flashing` for examples. + + .. versionchanged:: 0.3 + `with_categories` parameter added. + + .. versionchanged:: 0.9 + `category_filter` parameter added. + + :param with_categories: set to ``True`` to also receive categories. + :param category_filter: filter of categories to limit return values. Only + categories in the list will be returned. + """ + flashes = request_ctx.flashes + if flashes is None: + flashes = session.pop("_flashes") if "_flashes" in session else [] + request_ctx.flashes = flashes + if category_filter: + flashes = list(filter(lambda f: f[0] in category_filter, flashes)) + if not with_categories: + return [x[1] for x in flashes] + return flashes + + +def _prepare_send_file_kwargs(**kwargs: t.Any) -> dict[str, t.Any]: + if kwargs.get("max_age") is None: + kwargs["max_age"] = current_app.get_send_file_max_age + + kwargs.update( + environ=request.environ, + use_x_sendfile=current_app.config["USE_X_SENDFILE"], + response_class=current_app.response_class, + _root_path=current_app.root_path, # type: ignore + ) + return kwargs + + +def send_file( + path_or_file: os.PathLike | str | t.BinaryIO, + mimetype: str | None = None, + as_attachment: bool = False, + download_name: str | None = None, + conditional: bool = True, + etag: bool | str = True, + last_modified: datetime | int | float | None = None, + max_age: None | (int | t.Callable[[str | None], int | None]) = None, +) -> Response: + """Send the contents of a file to the client. + + The first argument can be a file path or a file-like object. Paths + are preferred in most cases because Werkzeug can manage the file and + get extra information from the path. Passing a file-like object + requires that the file is opened in binary mode, and is mostly + useful when building a file in memory with :class:`io.BytesIO`. + + Never pass file paths provided by a user. The path is assumed to be + trusted, so a user could craft a path to access a file you didn't + intend. Use :func:`send_from_directory` to safely serve + user-requested paths from within a directory. + + If the WSGI server sets a ``file_wrapper`` in ``environ``, it is + used, otherwise Werkzeug's built-in wrapper is used. Alternatively, + if the HTTP server supports ``X-Sendfile``, configuring Flask with + ``USE_X_SENDFILE = True`` will tell the server to send the given + path, which is much more efficient than reading it in Python. + + :param path_or_file: The path to the file to send, relative to the + current working directory if a relative path is given. + Alternatively, a file-like object opened in binary mode. Make + sure the file pointer is seeked to the start of the data. + :param mimetype: The MIME type to send for the file. If not + provided, it will try to detect it from the file name. + :param as_attachment: Indicate to a browser that it should offer to + save the file instead of displaying it. + :param download_name: The default name browsers will use when saving + the file. Defaults to the passed file name. + :param conditional: Enable conditional and range responses based on + request headers. Requires passing a file path and ``environ``. + :param etag: Calculate an ETag for the file, which requires passing + a file path. Can also be a string to use instead. + :param last_modified: The last modified time to send for the file, + in seconds. If not provided, it will try to detect it from the + file path. + :param max_age: How long the client should cache the file, in + seconds. If set, ``Cache-Control`` will be ``public``, otherwise + it will be ``no-cache`` to prefer conditional caching. + + .. versionchanged:: 2.0 + ``download_name`` replaces the ``attachment_filename`` + parameter. If ``as_attachment=False``, it is passed with + ``Content-Disposition: inline`` instead. + + .. versionchanged:: 2.0 + ``max_age`` replaces the ``cache_timeout`` parameter. + ``conditional`` is enabled and ``max_age`` is not set by + default. + + .. versionchanged:: 2.0 + ``etag`` replaces the ``add_etags`` parameter. It can be a + string to use instead of generating one. + + .. versionchanged:: 2.0 + Passing a file-like object that inherits from + :class:`~io.TextIOBase` will raise a :exc:`ValueError` rather + than sending an empty file. + + .. versionadded:: 2.0 + Moved the implementation to Werkzeug. This is now a wrapper to + pass some Flask-specific arguments. + + .. versionchanged:: 1.1 + ``filename`` may be a :class:`~os.PathLike` object. + + .. versionchanged:: 1.1 + Passing a :class:`~io.BytesIO` object supports range requests. + + .. versionchanged:: 1.0.3 + Filenames are encoded with ASCII instead of Latin-1 for broader + compatibility with WSGI servers. + + .. versionchanged:: 1.0 + UTF-8 filenames as specified in :rfc:`2231` are supported. + + .. versionchanged:: 0.12 + The filename is no longer automatically inferred from file + objects. If you want to use automatic MIME and etag support, + pass a filename via ``filename_or_fp`` or + ``attachment_filename``. + + .. versionchanged:: 0.12 + ``attachment_filename`` is preferred over ``filename`` for MIME + detection. + + .. versionchanged:: 0.9 + ``cache_timeout`` defaults to + :meth:`Flask.get_send_file_max_age`. + + .. versionchanged:: 0.7 + MIME guessing and etag support for file-like objects was + deprecated because it was unreliable. Pass a filename if you are + able to, otherwise attach an etag yourself. + + .. versionchanged:: 0.5 + The ``add_etags``, ``cache_timeout`` and ``conditional`` + parameters were added. The default behavior is to add etags. + + .. versionadded:: 0.2 + """ + return werkzeug.utils.send_file( # type: ignore[return-value] + **_prepare_send_file_kwargs( + path_or_file=path_or_file, + environ=request.environ, + mimetype=mimetype, + as_attachment=as_attachment, + download_name=download_name, + conditional=conditional, + etag=etag, + last_modified=last_modified, + max_age=max_age, + ) + ) + + +def send_from_directory( + directory: os.PathLike | str, + path: os.PathLike | str, + **kwargs: t.Any, +) -> Response: + """Send a file from within a directory using :func:`send_file`. + + .. code-block:: python + + @app.route("/uploads/") + def download_file(name): + return send_from_directory( + app.config['UPLOAD_FOLDER'], name, as_attachment=True + ) + + This is a secure way to serve files from a folder, such as static + files or uploads. Uses :func:`~werkzeug.security.safe_join` to + ensure the path coming from the client is not maliciously crafted to + point outside the specified directory. + + If the final path does not point to an existing regular file, + raises a 404 :exc:`~werkzeug.exceptions.NotFound` error. + + :param directory: The directory that ``path`` must be located under, + relative to the current application's root path. + :param path: The path to the file to send, relative to + ``directory``. + :param kwargs: Arguments to pass to :func:`send_file`. + + .. versionchanged:: 2.0 + ``path`` replaces the ``filename`` parameter. + + .. versionadded:: 2.0 + Moved the implementation to Werkzeug. This is now a wrapper to + pass some Flask-specific arguments. + + .. versionadded:: 0.5 + """ + return werkzeug.utils.send_from_directory( # type: ignore[return-value] + directory, path, **_prepare_send_file_kwargs(**kwargs) + ) + + +def get_root_path(import_name: str) -> str: + """Find the root path of a package, or the path that contains a + module. If it cannot be found, returns the current working + directory. + + Not to be confused with the value returned by :func:`find_package`. + + :meta private: + """ + # Module already imported and has a file attribute. Use that first. + mod = sys.modules.get(import_name) + + if mod is not None and hasattr(mod, "__file__") and mod.__file__ is not None: + return os.path.dirname(os.path.abspath(mod.__file__)) + + # Next attempt: check the loader. + loader = pkgutil.get_loader(import_name) + + # Loader does not exist or we're referring to an unloaded main + # module or a main module without path (interactive sessions), go + # with the current working directory. + if loader is None or import_name == "__main__": + return os.getcwd() + + if hasattr(loader, "get_filename"): + filepath = loader.get_filename(import_name) + 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. + + .. deprecated:: 2.3 + Will be removed in Flask 2.4. Use a lock inside the decorated function if + locking is needed. + + .. versionchanged:: 2.0 + Inherits from Werkzeug's ``cached_property`` (and ``property``). + """ + + def __init__( + self, + fget: t.Callable[[t.Any], t.Any], + name: str | None = None, + doc: str | None = None, + ) -> None: + import warnings + + warnings.warn( + "'locked_cached_property' is deprecated and will be removed in Flask 2.4." + " Use a lock inside the decorated function if locking is needed.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(fget, name=name, doc=doc) + self.lock = RLock() + + def __get__(self, obj: object, type: type = None) -> t.Any: # type: ignore + if obj is None: + return self + + with self.lock: + return super().__get__(obj, type=type) + + def __set__(self, obj: object, value: t.Any) -> None: + with self.lock: + super().__set__(obj, value) + + def __delete__(self, obj: object) -> None: + with self.lock: + super().__delete__(obj) + + +def is_ip(value: str) -> bool: + """Determine if the given string is an IP address. + + :param value: value to check + :type value: str + + :return: True if string is an IP address + :rtype: bool + + .. deprecated:: 2.3 + Will be removed in Flask 2.4. + """ + warnings.warn( + "The 'is_ip' function is deprecated and will be removed in Flask 2.4.", + DeprecationWarning, + stacklevel=2, + ) + + 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) -> list[str]: + out: list[str] = [name] + + if "." in name: + out.extend(_split_blueprint_path(name.rpartition(".")[0])) + + return out diff --git a/.venv/Lib/site-packages/flask/json/__init__.py b/.venv/Lib/site-packages/flask/json/__init__.py new file mode 100644 index 000000000..f15296fed --- /dev/null +++ b/.venv/Lib/site-packages/flask/json/__init__.py @@ -0,0 +1,170 @@ +from __future__ import annotations + +import json as _json +import typing as t + +from ..globals import current_app +from .provider import _default + +if t.TYPE_CHECKING: # pragma: no cover + from ..wrappers import Response + + +def dumps(obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.dumps() ` + method, otherwise it will use :func:`json.dumps`. + + :param obj: The data to serialize. + :param kwargs: Arguments passed to the ``dumps`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.dumps``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0.2 + :class:`decimal.Decimal` is supported by converting to a string. + + .. versionchanged:: 2.0 + ``encoding`` will be removed in Flask 2.1. + + .. versionchanged:: 1.0.3 + ``app`` can be passed directly, rather than requiring an app + context for configuration. + """ + if current_app: + return current_app.json.dumps(obj, **kwargs) + + kwargs.setdefault("default", _default) + return _json.dumps(obj, **kwargs) + + +def dump(obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None: + """Serialize data as JSON and write to a file. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.dump() ` + method, otherwise it will use :func:`json.dump`. + + :param obj: The data to serialize. + :param fp: A file opened for writing text. Should use the UTF-8 + encoding to be valid JSON. + :param kwargs: Arguments passed to the ``dump`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.dump``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0 + Writing to a binary file, and the ``encoding`` argument, will be + removed in Flask 2.1. + """ + if current_app: + current_app.json.dump(obj, fp, **kwargs) + else: + kwargs.setdefault("default", _default) + _json.dump(obj, fp, **kwargs) + + +def loads(s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.loads() ` + method, otherwise it will use :func:`json.loads`. + + :param s: Text or UTF-8 bytes. + :param kwargs: Arguments passed to the ``loads`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.loads``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0 + ``encoding`` will be removed in Flask 2.1. The data must be a + string or UTF-8 bytes. + + .. versionchanged:: 1.0.3 + ``app`` can be passed directly, rather than requiring an app + context for configuration. + """ + if current_app: + return current_app.json.loads(s, **kwargs) + + return _json.loads(s, **kwargs) + + +def load(fp: t.IO[t.AnyStr], **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON read from a file. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.load() ` + method, otherwise it will use :func:`json.load`. + + :param fp: A file opened for reading text or UTF-8 bytes. + :param kwargs: Arguments passed to the ``load`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.load``, allowing an app to override + the behavior. + + .. versionchanged:: 2.2 + The ``app`` parameter will be removed in Flask 2.3. + + .. versionchanged:: 2.0 + ``encoding`` will be removed in Flask 2.1. The file must be text + mode, or binary mode with UTF-8 bytes. + """ + if current_app: + return current_app.json.load(fp, **kwargs) + + return _json.load(fp, **kwargs) + + +def jsonify(*args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with the ``application/json`` + mimetype. A dict or list returned from a view will be converted to a + JSON response automatically without needing to call this. + + This requires an active request or application context, and calls + :meth:`app.json.response() `. + + In debug mode, the output is formatted with indentation to make it + easier to read. This may also be controlled by the provider. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + + .. versionchanged:: 2.2 + Calls ``current_app.json.response``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0.2 + :class:`decimal.Decimal` is supported by converting to a string. + + .. versionchanged:: 0.11 + Added support for serializing top-level arrays. This was a + security risk in ancient browsers. See :ref:`security-json`. + + .. versionadded:: 0.2 + """ + return current_app.json.response(*args, **kwargs) diff --git a/.venv/Lib/site-packages/flask/json/__pycache__/__init__.cpython-311.pyc b/.venv/Lib/site-packages/flask/json/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4b2610755e27a31631b52182b65b3906ea5ed95b GIT binary patch literal 6890 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 E3z6}XWdHyG literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask/json/__pycache__/provider.cpython-311.pyc b/.venv/Lib/site-packages/flask/json/__pycache__/provider.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7322c9e2cda35c389cde4d7987367a77b60ef05a GIT binary patch literal 9997 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 Z)}-2dvJ7IcpWYe%lDB-dK|AM#{|2R3={5iW literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask/json/__pycache__/tag.cpython-311.pyc b/.venv/Lib/site-packages/flask/json/__pycache__/tag.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6b2c69e6cd7424bc087b9c88cfde43a1b19dd5c3 GIT binary patch literal 15599 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

D-hwg_9LkI&89V9B~6oX03ik)NARH)R)x-7J`*x zVFYpp3d_?QUz6AKa8hsA&v__Y5ES{w^2yekUl{b{VxF! zurwq@`TyH=)`{SVqYmtWlM>4#S8cv)Nkajh$yJJI|J5XCLgAmPc34t)_2|J!p$9KMz&5@}&>jcfa4hdo8`uzQ5AGziizP z9A)bI_(prY(jG5cH+LB%;Kxp!9>&O$UBXfru`(3Ac*V6QA$7sj7O>Y`aIj+W=uBDf%IV?LhEfG=Sd_ zl!_>HSzAcN{cOs4^cBr0GT3BGNV6$+hZ|6pQa^ahYio#sp^)`+sDj|np1#{y`TAPv zh`x0Qb|u>Vy@fXxtPMb#*P+e6fjjeW&aV}3-MD?D96Q8s7@LkEIv3rs+|DM#MQqz< z{44rtT#C9iG=hJaPSllO;z5lzu^gcyB-k4H@7gGUYZj})VjjJe2Aa+zD?3ax zNe5pDK!PL|Z;q^ttaZKdB9qDG^S|^))IeZYmD`ze+g{ud+~xBRqCG1MYdtGBK8Oy# zA056MyqkV6vJriz5`Cr|euj%!30*Xw-Y=n~VR}DhSf(Pr=W`oekl0^(2BT#fnTKeS zMrFShpu3|K8*nnigx&*5D*J;hXWdGHC?G#EyU{L7Vk2sEq&>Gte zJMXT|aC9@=Q|oH&4K1Co?Fl0+#nVSo~Q|K z(C?1bVxe0I*h0N+09OSxy!dVwVn$KLQ$-4mMszT#@M;Ka3i;#32)7SviP8L6L8Xl<0yF|TT~CAB!6pdYVj^z#HQ%08lBHE>~OWbdVtPdkll zQrr{uFno$fL%*QiMN?pLLH{-kI!u}<)_id>P(#FcpmsqN!~?|beFArQy46} z?`Ao>%Yy6P6n2!|_XBqY)ZY})uj}3v4wl{b1EIg{zBk>kD6NI|h=_jnf{!Tg<9fkM zVxI^fzzdeAKcd`^>qRHp#O|8l1` to an instance of the class. + + :param app: An application instance. This will be stored as a + :class:`weakref.proxy` on the :attr:`_app` attribute. + + .. versionadded:: 2.2 + """ + + def __init__(self, app: Flask) -> None: + self._app = weakref.proxy(app) + + def dumps(self, obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON. + + :param obj: The data to serialize. + :param kwargs: May be passed to the underlying JSON library. + """ + raise NotImplementedError + + def dump(self, obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None: + """Serialize data as JSON and write to a file. + + :param obj: The data to serialize. + :param fp: A file opened for writing text. Should use the UTF-8 + encoding to be valid JSON. + :param kwargs: May be passed to the underlying JSON library. + """ + fp.write(self.dumps(obj, **kwargs)) + + def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON. + + :param s: Text or UTF-8 bytes. + :param kwargs: May be passed to the underlying JSON library. + """ + raise NotImplementedError + + def load(self, fp: t.IO[t.AnyStr], **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON read from a file. + + :param fp: A file opened for reading text or UTF-8 bytes. + :param kwargs: May be passed to the underlying JSON library. + """ + return self.loads(fp.read(), **kwargs) + + def _prepare_response_obj( + self, args: tuple[t.Any, ...], kwargs: dict[str, t.Any] + ) -> t.Any: + if args and kwargs: + raise TypeError("app.json.response() takes either args or kwargs, not both") + + if not args and not kwargs: + return None + + if len(args) == 1: + return args[0] + + return args or kwargs + + def response(self, *args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with the ``application/json`` + mimetype. + + The :func:`~flask.json.jsonify` function calls this method for + the current application. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + """ + obj = self._prepare_response_obj(args, kwargs) + return self._app.response_class(self.dumps(obj), mimetype="application/json") + + +def _default(o: t.Any) -> t.Any: + if isinstance(o, date): + return http_date(o) + + if isinstance(o, (decimal.Decimal, uuid.UUID)): + return str(o) + + if dataclasses and dataclasses.is_dataclass(o): + return dataclasses.asdict(o) + + if hasattr(o, "__html__"): + return str(o.__html__()) + + raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable") + + +class DefaultJSONProvider(JSONProvider): + """Provide JSON operations using Python's built-in :mod:`json` + library. Serializes the following additional data types: + + - :class:`datetime.datetime` and :class:`datetime.date` are + serialized to :rfc:`822` strings. This is the same as the HTTP + date format. + - :class:`uuid.UUID` is serialized to a string. + - :class:`dataclasses.dataclass` is passed to + :func:`dataclasses.asdict`. + - :class:`~markupsafe.Markup` (or any object with a ``__html__`` + method) will call the ``__html__`` method to get a string. + """ + + default: t.Callable[[t.Any], t.Any] = staticmethod( + _default + ) # type: ignore[assignment] + """Apply this function to any object that :meth:`json.dumps` does + not know how to serialize. It should return a valid JSON type or + raise a ``TypeError``. + """ + + ensure_ascii = True + """Replace non-ASCII characters with escape sequences. This may be + more compatible with some clients, but can be disabled for better + performance and size. + """ + + sort_keys = True + """Sort the keys in any serialized dicts. This may be useful for + some caching situations, but can be disabled for better performance. + When enabled, keys must all be strings, they are not converted + before sorting. + """ + + compact: bool | None = None + """If ``True``, or ``None`` out of debug mode, the :meth:`response` + output will not add indentation, newlines, or spaces. If ``False``, + or ``None`` in debug mode, it will use a non-compact representation. + """ + + mimetype = "application/json" + """The mimetype set in :meth:`response`.""" + + def dumps(self, obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON to a string. + + Keyword arguments are passed to :func:`json.dumps`. Sets some + parameter defaults from the :attr:`default`, + :attr:`ensure_ascii`, and :attr:`sort_keys` attributes. + + :param obj: The data to serialize. + :param kwargs: Passed to :func:`json.dumps`. + """ + kwargs.setdefault("default", self.default) + kwargs.setdefault("ensure_ascii", self.ensure_ascii) + kwargs.setdefault("sort_keys", self.sort_keys) + return json.dumps(obj, **kwargs) + + def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON from a string or bytes. + + :param s: Text or UTF-8 bytes. + :param kwargs: Passed to :func:`json.loads`. + """ + return json.loads(s, **kwargs) + + def response(self, *args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with it. The response mimetype + will be "application/json" and can be changed with + :attr:`mimetype`. + + If :attr:`compact` is ``False`` or debug mode is enabled, the + output will be formatted to be easier to read. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + """ + obj = self._prepare_response_obj(args, kwargs) + dump_args: dict[str, t.Any] = {} + + if (self.compact is None and self._app.debug) or self.compact is False: + dump_args.setdefault("indent", 2) + else: + dump_args.setdefault("separators", (",", ":")) + + return self._app.response_class( + f"{self.dumps(obj, **dump_args)}\n", mimetype=self.mimetype + ) diff --git a/.venv/Lib/site-packages/flask/json/tag.py b/.venv/Lib/site-packages/flask/json/tag.py new file mode 100644 index 000000000..91cc4412d --- /dev/null +++ b/.venv/Lib/site-packages/flask/json/tag.py @@ -0,0 +1,314 @@ +""" +Tagged JSON +~~~~~~~~~~~ + +A compact representation for lossless serialization of non-standard JSON +types. :class:`~flask.sessions.SecureCookieSessionInterface` uses this +to serialize the session data, but it may be useful in other places. It +can be extended to support other types. + +.. autoclass:: TaggedJSONSerializer + :members: + +.. autoclass:: JSONTag + :members: + +Let's see an example that adds support for +:class:`~collections.OrderedDict`. Dicts don't have an order in JSON, so +to handle this we will dump the items as a list of ``[key, value]`` +pairs. Subclass :class:`JSONTag` and give it the new key ``' od'`` to +identify the type. The session serializer processes dicts first, so +insert the new tag at the front of the order since ``OrderedDict`` must +be processed before ``dict``. + +.. code-block:: python + + from flask.json.tag import JSONTag + + class TagOrderedDict(JSONTag): + __slots__ = ('serializer',) + key = ' od' + + def check(self, value): + return isinstance(value, OrderedDict) + + def to_json(self, value): + return [[k, self.serializer.tag(v)] for k, v in iteritems(value)] + + def to_python(self, value): + return OrderedDict(value) + + app.session_interface.serializer.register(TagOrderedDict, index=0) +""" +from __future__ import annotations + +import typing as t +from base64 import b64decode +from base64 import b64encode +from datetime import datetime +from uuid import UUID + +from markupsafe import Markup +from werkzeug.http import http_date +from werkzeug.http import parse_date + +from ..json import dumps +from ..json import loads + + +class JSONTag: + """Base class for defining type tags for :class:`TaggedJSONSerializer`.""" + + __slots__ = ("serializer",) + + #: The tag to mark the serialized object with. If ``None``, this tag is + #: only used as an intermediate step during tagging. + key: str | None = None + + def __init__(self, serializer: TaggedJSONSerializer) -> None: + """Create a tagger for the given serializer.""" + self.serializer = serializer + + def check(self, value: t.Any) -> bool: + """Check if the given value should be tagged by this tag.""" + raise NotImplementedError + + def to_json(self, value: t.Any) -> t.Any: + """Convert the Python object to an object that is a valid JSON type. + The tag will be added later.""" + raise NotImplementedError + + def to_python(self, value: t.Any) -> t.Any: + """Convert the JSON representation back to the correct type. The tag + will already be removed.""" + raise NotImplementedError + + def tag(self, value: t.Any) -> t.Any: + """Convert the value to a valid JSON type and add the tag structure + around it.""" + return {self.key: self.to_json(value)} + + +class TagDict(JSONTag): + """Tag for 1-item dicts whose only key matches a registered tag. + + Internally, the dict key is suffixed with `__`, and the suffix is removed + when deserializing. + """ + + __slots__ = () + key = " di" + + def check(self, value: t.Any) -> bool: + return ( + isinstance(value, dict) + and len(value) == 1 + and next(iter(value)) in self.serializer.tags + ) + + def to_json(self, value: t.Any) -> t.Any: + key = next(iter(value)) + return {f"{key}__": self.serializer.tag(value[key])} + + def to_python(self, value: t.Any) -> t.Any: + key = next(iter(value)) + return {key[:-2]: value[key]} + + +class PassDict(JSONTag): + __slots__ = () + + def check(self, value: t.Any) -> bool: + return isinstance(value, dict) + + def to_json(self, value: t.Any) -> t.Any: + # JSON objects may only have string keys, so don't bother tagging the + # key here. + return {k: self.serializer.tag(v) for k, v in value.items()} + + tag = to_json + + +class TagTuple(JSONTag): + __slots__ = () + key = " t" + + def check(self, value: t.Any) -> bool: + return isinstance(value, tuple) + + def to_json(self, value: t.Any) -> t.Any: + return [self.serializer.tag(item) for item in value] + + def to_python(self, value: t.Any) -> t.Any: + return tuple(value) + + +class PassList(JSONTag): + __slots__ = () + + def check(self, value: t.Any) -> bool: + return isinstance(value, list) + + def to_json(self, value: t.Any) -> t.Any: + return [self.serializer.tag(item) for item in value] + + tag = to_json + + +class TagBytes(JSONTag): + __slots__ = () + key = " b" + + def check(self, value: t.Any) -> bool: + return isinstance(value, bytes) + + def to_json(self, value: t.Any) -> t.Any: + return b64encode(value).decode("ascii") + + def to_python(self, value: t.Any) -> t.Any: + return b64decode(value) + + +class TagMarkup(JSONTag): + """Serialize anything matching the :class:`~markupsafe.Markup` API by + having a ``__html__`` method to the result of that method. Always + deserializes to an instance of :class:`~markupsafe.Markup`.""" + + __slots__ = () + key = " m" + + def check(self, value: t.Any) -> bool: + return callable(getattr(value, "__html__", None)) + + def to_json(self, value: t.Any) -> t.Any: + return str(value.__html__()) + + def to_python(self, value: t.Any) -> t.Any: + return Markup(value) + + +class TagUUID(JSONTag): + __slots__ = () + key = " u" + + def check(self, value: t.Any) -> bool: + return isinstance(value, UUID) + + def to_json(self, value: t.Any) -> t.Any: + return value.hex + + def to_python(self, value: t.Any) -> t.Any: + return UUID(value) + + +class TagDateTime(JSONTag): + __slots__ = () + key = " d" + + def check(self, value: t.Any) -> bool: + return isinstance(value, datetime) + + def to_json(self, value: t.Any) -> t.Any: + return http_date(value) + + def to_python(self, value: t.Any) -> t.Any: + return parse_date(value) + + +class TaggedJSONSerializer: + """Serializer that uses a tag system to compactly represent objects that + are not JSON types. Passed as the intermediate serializer to + :class:`itsdangerous.Serializer`. + + The following extra types are supported: + + * :class:`dict` + * :class:`tuple` + * :class:`bytes` + * :class:`~markupsafe.Markup` + * :class:`~uuid.UUID` + * :class:`~datetime.datetime` + """ + + __slots__ = ("tags", "order") + + #: Tag classes to bind when creating the serializer. Other tags can be + #: added later using :meth:`~register`. + default_tags = [ + TagDict, + PassDict, + TagTuple, + PassList, + TagBytes, + TagMarkup, + TagUUID, + TagDateTime, + ] + + def __init__(self) -> None: + self.tags: dict[str, JSONTag] = {} + self.order: list[JSONTag] = [] + + for cls in self.default_tags: + self.register(cls) + + def register( + self, + tag_class: type[JSONTag], + force: bool = False, + index: int | None = None, + ) -> None: + """Register a new tag with this serializer. + + :param tag_class: tag class to register. Will be instantiated with this + serializer instance. + :param force: overwrite an existing tag. If false (default), a + :exc:`KeyError` is raised. + :param index: index to insert the new tag in the tag order. Useful when + the new tag is a special case of an existing tag. If ``None`` + (default), the tag is appended to the end of the order. + + :raise KeyError: if the tag key is already registered and ``force`` is + not true. + """ + tag = tag_class(self) + key = tag.key + + if key is not None: + if not force and key in self.tags: + raise KeyError(f"Tag '{key}' is already registered.") + + self.tags[key] = tag + + if index is None: + self.order.append(tag) + else: + self.order.insert(index, tag) + + def tag(self, value: t.Any) -> dict[str, t.Any]: + """Convert a value to a tagged representation if necessary.""" + for tag in self.order: + if tag.check(value): + return tag.tag(value) + + return value + + def untag(self, value: dict[str, t.Any]) -> t.Any: + """Convert a tagged representation back to the original type.""" + if len(value) != 1: + return value + + key = next(iter(value)) + + if key not in self.tags: + return value + + return self.tags[key].to_python(value[key]) + + def dumps(self, value: t.Any) -> str: + """Tag the value and dump it to a compact JSON string.""" + return dumps(self.tag(value), separators=(",", ":")) + + def loads(self, value: str) -> t.Any: + """Load data from a JSON string and deserialized any tagged objects.""" + return loads(value, object_hook=self.untag) diff --git a/.venv/Lib/site-packages/flask/logging.py b/.venv/Lib/site-packages/flask/logging.py new file mode 100644 index 000000000..99f6be85b --- /dev/null +++ b/.venv/Lib/site-packages/flask/logging.py @@ -0,0 +1,76 @@ +from __future__ import annotations + +import logging +import sys +import typing as t + +from werkzeug.local import LocalProxy + +from .globals import request + +if t.TYPE_CHECKING: # pragma: no cover + from .app import Flask + + +@LocalProxy +def wsgi_errors_stream() -> t.TextIO: + """Find the most appropriate error stream for the application. If a request + is active, log to ``wsgi.errors``, otherwise use ``sys.stderr``. + + If you configure your own :class:`logging.StreamHandler`, you may want to + use this for the stream. If you are using file or dict configuration and + can't import this directly, you can refer to it as + ``ext://flask.logging.wsgi_errors_stream``. + """ + return request.environ["wsgi.errors"] if request else sys.stderr + + +def has_level_handler(logger: logging.Logger) -> bool: + """Check if there is a handler in the logging chain that will handle the + given logger's :meth:`effective level <~logging.Logger.getEffectiveLevel>`. + """ + level = logger.getEffectiveLevel() + current = logger + + while current: + if any(handler.level <= level for handler in current.handlers): + return True + + if not current.propagate: + break + + current = current.parent # type: ignore + + return False + + +#: Log messages to :func:`~flask.logging.wsgi_errors_stream` with the format +#: ``[%(asctime)s] %(levelname)s in %(module)s: %(message)s``. +default_handler = logging.StreamHandler(wsgi_errors_stream) # type: ignore +default_handler.setFormatter( + logging.Formatter("[%(asctime)s] %(levelname)s in %(module)s: %(message)s") +) + + +def create_logger(app: Flask) -> logging.Logger: + """Get the Flask app's logger and configure it if needed. + + The logger name will be the same as + :attr:`app.import_name `. + + When :attr:`~flask.Flask.debug` is enabled, set the logger level to + :data:`logging.DEBUG` if it is not set. + + If there is no handler for the logger's effective level, add a + :class:`~logging.StreamHandler` for + :func:`~flask.logging.wsgi_errors_stream` with a basic format. + """ + logger = logging.getLogger(app.name) + + if app.debug and not logger.level: + logger.setLevel(logging.DEBUG) + + if not has_level_handler(logger): + logger.addHandler(default_handler) + + return logger diff --git a/.venv/Lib/site-packages/flask/py.typed b/.venv/Lib/site-packages/flask/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/.venv/Lib/site-packages/flask/scaffold.py b/.venv/Lib/site-packages/flask/scaffold.py new file mode 100644 index 000000000..6af6906a4 --- /dev/null +++ b/.venv/Lib/site-packages/flask/scaffold.py @@ -0,0 +1,923 @@ +from __future__ import annotations + +import importlib.util +import os +import pathlib +import pkgutil +import sys +import typing as t +from collections import defaultdict +from datetime import timedelta +from functools import update_wrapper + +from jinja2 import FileSystemLoader +from werkzeug.exceptions import default_exceptions +from werkzeug.exceptions import HTTPException +from werkzeug.utils import cached_property + +from . import typing as ft +from .cli import AppGroup +from .globals import current_app +from .helpers import get_root_path +from .helpers import send_from_directory +from .templating import _default_template_ctx_processor + +if t.TYPE_CHECKING: # pragma: no cover + from .wrappers import Response + +# a singleton sentinel value for parameter defaults +_sentinel = object() + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) +T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable) +T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable) +T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable) +T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) +T_template_context_processor = t.TypeVar( + "T_template_context_processor", bound=ft.TemplateContextProcessorCallable +) +T_url_defaults = t.TypeVar("T_url_defaults", bound=ft.URLDefaultCallable) +T_url_value_preprocessor = t.TypeVar( + "T_url_value_preprocessor", bound=ft.URLValuePreprocessorCallable +) +T_route = t.TypeVar("T_route", bound=ft.RouteCallable) + + +def setupmethod(f: F) -> F: + f_name = f.__name__ + + def wrapper_func(self, *args: t.Any, **kwargs: t.Any) -> t.Any: + self._check_setup_finished(f_name) + return f(self, *args, **kwargs) + + return t.cast(F, update_wrapper(wrapper_func, f)) + + +class Scaffold: + """Common behavior shared between :class:`~flask.Flask` and + :class:`~flask.blueprints.Blueprint`. + + :param import_name: The import name of the module where this object + is defined. Usually :attr:`__name__` should be used. + :param static_folder: Path to a folder of static files to serve. + If this is set, a static route will be added. + :param static_url_path: URL prefix for the static route. + :param template_folder: Path to a folder containing template files. + for rendering. If this is set, a Jinja loader will be added. + :param root_path: The path that static, template, and resource files + are relative to. Typically not set, it is discovered based on + the ``import_name``. + + .. versionadded:: 2.0 + """ + + name: str + _static_folder: str | None = None + _static_url_path: str | None = None + + def __init__( + self, + import_name: str, + static_folder: str | os.PathLike | None = None, + static_url_path: str | None = None, + template_folder: str | os.PathLike | None = None, + root_path: str | None = None, + ): + #: The name of the package or module that this object belongs + #: to. Do not change this once it is set by the constructor. + self.import_name = import_name + + self.static_folder = static_folder # type: ignore + self.static_url_path = static_url_path + + #: The path to the templates folder, relative to + #: :attr:`root_path`, to add to the template loader. ``None`` if + #: templates should not be added. + self.template_folder = template_folder + + if root_path is None: + root_path = get_root_path(self.import_name) + + #: Absolute path to the package on the filesystem. Used to look + #: up resources contained in the package. + self.root_path = root_path + + #: The Click command group for registering CLI commands for this + #: object. The commands are available from the ``flask`` command + #: once the application has been discovered and blueprints have + #: been registered. + self.cli = AppGroup() + + #: A dictionary mapping endpoint names to view functions. + #: + #: To register a view function, use the :meth:`route` decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.view_functions: dict[str, t.Callable] = {} + + #: A data structure of registered error handlers, in the format + #: ``{scope: {code: {class: handler}}}``. The ``scope`` key is + #: the name of a blueprint the handlers are active for, or + #: ``None`` for all requests. The ``code`` key is the HTTP + #: status code for ``HTTPException``, or ``None`` for + #: other exceptions. The innermost dictionary maps exception + #: classes to handler functions. + #: + #: To register an error handler, use the :meth:`errorhandler` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.error_handler_spec: dict[ + ft.AppOrBlueprintKey, + dict[int | None, dict[type[Exception], ft.ErrorHandlerCallable]], + ] = defaultdict(lambda: defaultdict(dict)) + + #: A data structure of functions to call at the beginning of + #: each request, in the format ``{scope: [functions]}``. The + #: ``scope`` key is the name of a blueprint the functions are + #: active for, or ``None`` for all requests. + #: + #: To register a function, use the :meth:`before_request` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.before_request_funcs: dict[ + ft.AppOrBlueprintKey, list[ft.BeforeRequestCallable] + ] = defaultdict(list) + + #: A data structure of functions to call at the end of each + #: request, in the format ``{scope: [functions]}``. The + #: ``scope`` key is the name of a blueprint the functions are + #: active for, or ``None`` for all requests. + #: + #: To register a function, use the :meth:`after_request` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.after_request_funcs: dict[ + ft.AppOrBlueprintKey, list[ft.AfterRequestCallable] + ] = defaultdict(list) + + #: A data structure of functions to call at the end of each + #: request even if an exception is raised, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the :meth:`teardown_request` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.teardown_request_funcs: dict[ + ft.AppOrBlueprintKey, list[ft.TeardownCallable] + ] = defaultdict(list) + + #: A data structure of functions to call to pass extra context + #: values when rendering templates, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the :meth:`context_processor` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.template_context_processors: dict[ + ft.AppOrBlueprintKey, list[ft.TemplateContextProcessorCallable] + ] = defaultdict(list, {None: [_default_template_ctx_processor]}) + + #: A data structure of functions to call to modify the keyword + #: arguments passed to the view function, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the + #: :meth:`url_value_preprocessor` decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.url_value_preprocessors: dict[ + ft.AppOrBlueprintKey, + list[ft.URLValuePreprocessorCallable], + ] = defaultdict(list) + + #: A data structure of functions to call to modify the keyword + #: arguments when generating URLs, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the :meth:`url_defaults` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.url_default_functions: dict[ + ft.AppOrBlueprintKey, list[ft.URLDefaultCallable] + ] = defaultdict(list) + + def __repr__(self) -> str: + return f"<{type(self).__name__} {self.name!r}>" + + def _check_setup_finished(self, f_name: str) -> None: + raise NotImplementedError + + @property + def static_folder(self) -> str | None: + """The absolute path to the configured static folder. ``None`` + if no static folder is set. + """ + if self._static_folder is not None: + return os.path.join(self.root_path, self._static_folder) + else: + return None + + @static_folder.setter + def static_folder(self, value: str | os.PathLike | None) -> None: + if value is not None: + value = os.fspath(value).rstrip(r"\/") + + self._static_folder = value + + @property + def has_static_folder(self) -> bool: + """``True`` if :attr:`static_folder` is set. + + .. versionadded:: 0.5 + """ + return self.static_folder is not None + + @property + def static_url_path(self) -> str | None: + """The URL prefix that the static route will be accessible from. + + If it was not configured during init, it is derived from + :attr:`static_folder`. + """ + if self._static_url_path is not None: + return self._static_url_path + + if self.static_folder is not None: + basename = os.path.basename(self.static_folder) + return f"/{basename}".rstrip("/") + + return None + + @static_url_path.setter + def static_url_path(self, value: str | None) -> None: + if value is not None: + value = value.rstrip("/") + + self._static_url_path = value + + def get_send_file_max_age(self, filename: str | None) -> int | None: + """Used by :func:`send_file` to determine the ``max_age`` cache + value for a given file path if it wasn't passed. + + By default, this returns :data:`SEND_FILE_MAX_AGE_DEFAULT` from + the configuration of :data:`~flask.current_app`. This defaults + to ``None``, which tells the browser to use conditional requests + instead of a timed cache, which is usually preferable. + + .. versionchanged:: 2.0 + The default configuration is ``None`` instead of 12 hours. + + .. versionadded:: 0.9 + """ + value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"] + + if value is None: + return None + + if isinstance(value, timedelta): + return int(value.total_seconds()) + + return value + + def send_static_file(self, filename: str) -> Response: + """The view function used to serve files from + :attr:`static_folder`. A route is automatically registered for + this view at :attr:`static_url_path` if :attr:`static_folder` is + set. + + .. versionadded:: 0.5 + """ + if not self.has_static_folder: + raise RuntimeError("'static_folder' must be set to serve static_files.") + + # send_file only knows to call get_send_file_max_age on the app, + # call it here so it works for blueprints too. + max_age = self.get_send_file_max_age(filename) + return send_from_directory( + t.cast(str, self.static_folder), filename, max_age=max_age + ) + + @cached_property + def jinja_loader(self) -> FileSystemLoader | None: + """The Jinja loader for this object's templates. By default this + is a class :class:`jinja2.loaders.FileSystemLoader` to + :attr:`template_folder` if it is set. + + .. versionadded:: 0.5 + """ + if self.template_folder is not None: + return FileSystemLoader(os.path.join(self.root_path, self.template_folder)) + else: + return None + + def open_resource(self, resource: str, mode: str = "rb") -> t.IO[t.AnyStr]: + """Open a resource file relative to :attr:`root_path` for + reading. + + For example, if the file ``schema.sql`` is next to the file + ``app.py`` where the ``Flask`` app is defined, it can be opened + with: + + .. code-block:: python + + with app.open_resource("schema.sql") as f: + conn.executescript(f.read()) + + :param resource: Path to the resource relative to + :attr:`root_path`. + :param mode: Open the file in this mode. Only reading is + supported, valid values are "r" (or "rt") and "rb". + """ + if mode not in {"r", "rt", "rb"}: + raise ValueError("Resources can only be opened for reading.") + + return open(os.path.join(self.root_path, resource), mode) + + def _method_route( + self, + method: str, + rule: str, + options: dict, + ) -> t.Callable[[T_route], T_route]: + if "methods" in options: + raise TypeError("Use the 'route' decorator to use the 'methods' argument.") + + return self.route(rule, methods=[method], **options) + + @setupmethod + def get(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["GET"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("GET", rule, options) + + @setupmethod + def post(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["POST"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("POST", rule, options) + + @setupmethod + def put(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["PUT"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("PUT", rule, options) + + @setupmethod + def delete(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["DELETE"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("DELETE", rule, options) + + @setupmethod + def patch(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["PATCH"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("PATCH", rule, options) + + @setupmethod + def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Decorate a view function to register it with the given URL + rule and options. Calls :meth:`add_url_rule`, which has more + details about the implementation. + + .. code-block:: python + + @app.route("/") + def index(): + return "Hello, World!" + + See :ref:`url-route-registrations`. + + The endpoint name for the route defaults to the name of the view + function if the ``endpoint`` parameter isn't passed. + + The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` and + ``OPTIONS`` are added automatically. + + :param rule: The URL rule string. + :param options: Extra options passed to the + :class:`~werkzeug.routing.Rule` object. + """ + + def decorator(f: T_route) -> T_route: + endpoint = options.pop("endpoint", None) + self.add_url_rule(rule, endpoint, f, **options) + return f + + return decorator + + @setupmethod + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + provide_automatic_options: bool | None = None, + **options: t.Any, + ) -> None: + """Register a rule for routing incoming requests and building + URLs. The :meth:`route` decorator is a shortcut to call this + with the ``view_func`` argument. These are equivalent: + + .. code-block:: python + + @app.route("/") + def index(): + ... + + .. code-block:: python + + def index(): + ... + + app.add_url_rule("/", view_func=index) + + See :ref:`url-route-registrations`. + + The endpoint name for the route defaults to the name of the view + function if the ``endpoint`` parameter isn't passed. An error + will be raised if a function has already been registered for the + endpoint. + + The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` is + always added automatically, and ``OPTIONS`` is added + automatically by default. + + ``view_func`` does not necessarily need to be passed, but if the + rule should participate in routing an endpoint name must be + associated with a view function at some point with the + :meth:`endpoint` decorator. + + .. code-block:: python + + app.add_url_rule("/", endpoint="index") + + @app.endpoint("index") + def index(): + ... + + If ``view_func`` has a ``required_methods`` attribute, those + methods are added to the passed and automatic methods. If it + has a ``provide_automatic_methods`` attribute, it is used as the + default if the parameter is not passed. + + :param rule: The URL rule string. + :param endpoint: The endpoint name to associate with the rule + and view function. Used when routing and building URLs. + Defaults to ``view_func.__name__``. + :param view_func: The view function to associate with the + endpoint name. + :param provide_automatic_options: Add the ``OPTIONS`` method and + respond to ``OPTIONS`` requests automatically. + :param options: Extra options passed to the + :class:`~werkzeug.routing.Rule` object. + """ + raise NotImplementedError + + @setupmethod + def endpoint(self, endpoint: str) -> t.Callable[[F], F]: + """Decorate a view function to register it for the given + endpoint. Used if a rule is added without a ``view_func`` with + :meth:`add_url_rule`. + + .. code-block:: python + + app.add_url_rule("/ex", endpoint="example") + + @app.endpoint("example") + def example(): + ... + + :param endpoint: The endpoint name to associate with the view + function. + """ + + def decorator(f: F) -> F: + self.view_functions[endpoint] = f + return f + + return decorator + + @setupmethod + def before_request(self, f: T_before_request) -> T_before_request: + """Register a function to run before each request. + + For example, this can be used to open a database connection, or + to load the logged in user from the session. + + .. code-block:: python + + @app.before_request + def load_user(): + if "user_id" in session: + g.user = db.session.get(session["user_id"]) + + The function will be called without any arguments. If it returns + a non-``None`` value, the value is handled as if it was the + return value from the view, and further request handling is + stopped. + + This is available on both app and blueprint objects. When used on an app, this + executes before every request. When used on a blueprint, this executes before + every request that the blueprint handles. To register with a blueprint and + execute before every request, use :meth:`.Blueprint.before_app_request`. + """ + self.before_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def after_request(self, f: T_after_request) -> T_after_request: + """Register a function to run after each request to this object. + + The function is called with the response object, and must return + a response object. This allows the functions to modify or + replace the response before it is sent. + + If a function raises an exception, any remaining + ``after_request`` functions will not be called. Therefore, this + should not be used for actions that must execute, such as to + close resources. Use :meth:`teardown_request` for that. + + This is available on both app and blueprint objects. When used on an app, this + executes after every request. When used on a blueprint, this executes after + every request that the blueprint handles. To register with a blueprint and + execute after every request, use :meth:`.Blueprint.after_app_request`. + """ + self.after_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def teardown_request(self, f: T_teardown) -> T_teardown: + """Register a function to be called when the request context is + popped. Typically this happens at the end of each request, but + contexts may be pushed manually as well during testing. + + .. code-block:: python + + with app.test_request_context(): + ... + + When the ``with`` block exits (or ``ctx.pop()`` is called), the + teardown functions are called just before the request context is + made inactive. + + When a teardown function was called because of an unhandled + exception it will be passed an error object. If an + :meth:`errorhandler` is registered, it will handle the exception + and the teardown will not receive it. + + Teardown functions must avoid raising exceptions. If they + execute code that might fail they must surround that code with a + ``try``/``except`` block and log any errors. + + The return values of teardown functions are ignored. + + This is available on both app and blueprint objects. When used on an app, this + executes after every request. When used on a blueprint, this executes after + every request that the blueprint handles. To register with a blueprint and + execute after every request, use :meth:`.Blueprint.teardown_app_request`. + """ + self.teardown_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def context_processor( + self, + f: T_template_context_processor, + ) -> T_template_context_processor: + """Registers a template context processor function. These functions run before + rendering a template. The keys of the returned dict are added as variables + available in the template. + + This is available on both app and blueprint objects. When used on an app, this + is called for every rendered template. When used on a blueprint, this is called + for templates rendered from the blueprint's views. To register with a blueprint + and affect every template, use :meth:`.Blueprint.app_context_processor`. + """ + self.template_context_processors[None].append(f) + return f + + @setupmethod + def url_value_preprocessor( + self, + f: T_url_value_preprocessor, + ) -> T_url_value_preprocessor: + """Register a URL value preprocessor function for all view + functions in the application. These functions will be called before the + :meth:`before_request` functions. + + The function can modify the values captured from the matched url before + they are passed to the view. For example, this can be used to pop a + common language code value and place it in ``g`` rather than pass it to + every view. + + The function is passed the endpoint name and values dict. The return + value is ignored. + + This is available on both app and blueprint objects. When used on an app, this + is called for every request. When used on a blueprint, this is called for + requests that the blueprint handles. To register with a blueprint and affect + every request, use :meth:`.Blueprint.app_url_value_preprocessor`. + """ + self.url_value_preprocessors[None].append(f) + return f + + @setupmethod + def url_defaults(self, f: T_url_defaults) -> T_url_defaults: + """Callback function for URL defaults for all view functions of the + application. It's called with the endpoint and values and should + update the values passed in place. + + This is available on both app and blueprint objects. When used on an app, this + is called for every request. When used on a blueprint, this is called for + requests that the blueprint handles. To register with a blueprint and affect + every request, use :meth:`.Blueprint.app_url_defaults`. + """ + self.url_default_functions[None].append(f) + return f + + @setupmethod + def errorhandler( + self, code_or_exception: type[Exception] | int + ) -> t.Callable[[T_error_handler], T_error_handler]: + """Register a function to handle errors by code or exception class. + + A decorator that is used to register a function given an + error code. Example:: + + @app.errorhandler(404) + def page_not_found(error): + return 'This page does not exist', 404 + + You can also register handlers for arbitrary exceptions:: + + @app.errorhandler(DatabaseError) + def special_exception_handler(error): + return 'Database connection failed', 500 + + This is available on both app and blueprint objects. When used on an app, this + can handle errors from every request. When used on a blueprint, this can handle + errors from requests that the blueprint handles. To register with a blueprint + and affect every request, use :meth:`.Blueprint.app_errorhandler`. + + .. versionadded:: 0.7 + Use :meth:`register_error_handler` instead of modifying + :attr:`error_handler_spec` directly, for application wide error + handlers. + + .. versionadded:: 0.7 + One can now additionally also register custom exception types + that do not necessarily have to be a subclass of the + :class:`~werkzeug.exceptions.HTTPException` class. + + :param code_or_exception: the code as integer for the handler, or + an arbitrary exception + """ + + def decorator(f: T_error_handler) -> T_error_handler: + self.register_error_handler(code_or_exception, f) + return f + + return decorator + + @setupmethod + def register_error_handler( + self, + code_or_exception: type[Exception] | int, + f: ft.ErrorHandlerCallable, + ) -> None: + """Alternative error attach function to the :meth:`errorhandler` + decorator that is more straightforward to use for non decorator + usage. + + .. versionadded:: 0.7 + """ + exc_class, code = self._get_exc_class_and_code(code_or_exception) + self.error_handler_spec[None][code][exc_class] = f + + @staticmethod + def _get_exc_class_and_code( + exc_class_or_code: type[Exception] | int, + ) -> tuple[type[Exception], int | None]: + """Get the exception class being handled. For HTTP status codes + or ``HTTPException`` subclasses, return both the exception and + status code. + + :param exc_class_or_code: Any exception class, or an HTTP status + code as an integer. + """ + exc_class: type[Exception] + + if isinstance(exc_class_or_code, int): + try: + exc_class = default_exceptions[exc_class_or_code] + except KeyError: + raise ValueError( + f"'{exc_class_or_code}' is not a recognized HTTP" + " error code. Use a subclass of HTTPException with" + " that code instead." + ) from None + else: + exc_class = exc_class_or_code + + if isinstance(exc_class, Exception): + raise TypeError( + f"{exc_class!r} is an instance, not a class. Handlers" + " can only be registered for Exception classes or HTTP" + " error codes." + ) + + if not issubclass(exc_class, Exception): + raise ValueError( + f"'{exc_class.__name__}' is not a subclass of Exception." + " Handlers can only be registered for Exception classes" + " or HTTP error codes." + ) + + if issubclass(exc_class, HTTPException): + return exc_class, exc_class.code + else: + return exc_class, None + + +def _endpoint_from_view_func(view_func: t.Callable) -> str: + """Internal helper that returns the default endpoint for a given + function. This always is the function name. + """ + assert view_func is not None, "expected view func if endpoint is not provided." + return view_func.__name__ + + +def _matching_loader_thinks_module_is_package(loader, mod_name): + """Attempt to figure out if the given name is a package or a module. + + :param: loader: The loader that handled the name. + :param mod_name: The name of the package or module. + """ + # Use loader.is_package if it's available. + if hasattr(loader, "is_package"): + return loader.is_package(mod_name) + + cls = type(loader) + + # NamespaceLoader doesn't implement is_package, but all names it + # loads must be packages. + if cls.__module__ == "_frozen_importlib" and cls.__name__ == "NamespaceLoader": + return True + + # Otherwise we need to fail with an error that explains what went + # wrong. + raise AttributeError( + f"'{cls.__name__}.is_package()' must be implemented for PEP 302" + f" import hooks." + ) + + +def _path_is_relative_to(path: pathlib.PurePath, base: str) -> bool: + # Path.is_relative_to doesn't exist until Python 3.9 + try: + path.relative_to(base) + return True + except ValueError: + return False + + +def _find_package_path(import_name): + """Find the path that contains the package or module.""" + root_mod_name, _, _ = import_name.partition(".") + + try: + root_spec = importlib.util.find_spec(root_mod_name) + + if root_spec is None: + raise ValueError("not found") + # ImportError: the machinery told us it does not exist + # ValueError: + # - the module name was invalid + # - the module name is __main__ + # - *we* raised `ValueError` due to `root_spec` being `None` + except (ImportError, ValueError): + pass # handled below + else: + # namespace package + if root_spec.origin in {"namespace", None}: + package_spec = importlib.util.find_spec(import_name) + if package_spec is not None and package_spec.submodule_search_locations: + # Pick the path in the namespace that contains the submodule. + package_path = pathlib.Path( + os.path.commonpath(package_spec.submodule_search_locations) + ) + search_locations = ( + location + for location in root_spec.submodule_search_locations + if _path_is_relative_to(package_path, location) + ) + else: + # Pick the first path. + search_locations = iter(root_spec.submodule_search_locations) + return os.path.dirname(next(search_locations)) + # a package (with __init__.py) + elif root_spec.submodule_search_locations: + return os.path.dirname(os.path.dirname(root_spec.origin)) + # just a normal module + else: + return os.path.dirname(root_spec.origin) + + # we were unable to find the `package_path` using PEP 451 loaders + loader = pkgutil.get_loader(root_mod_name) + + if loader is None or root_mod_name == "__main__": + # import name is not found, or interactive/main module + return os.getcwd() + + if hasattr(loader, "get_filename"): + filename = loader.get_filename(root_mod_name) + elif hasattr(loader, "archive"): + # zipimporter's loader.archive points to the .egg or .zip file. + filename = loader.archive + else: + # At least one loader is missing both get_filename and archive: + # Google App Engine's HardenedModulesHook, use __file__. + filename = importlib.import_module(root_mod_name).__file__ + + package_path = os.path.abspath(os.path.dirname(filename)) + + # If the imported name is a package, filename is currently pointing + # to the root of the package, need to get the current directory. + if _matching_loader_thinks_module_is_package(loader, root_mod_name): + package_path = os.path.dirname(package_path) + + return package_path + + +def find_package(import_name: str): + """Find the prefix that a package is installed under, and the path + that it would be imported from. + + The prefix is the directory containing the standard directory + hierarchy (lib, bin, etc.). If the package is not installed to the + system (:attr:`sys.prefix`) or a virtualenv (``site-packages``), + ``None`` is returned. + + The path is the entry in :attr:`sys.path` that contains the package + for import. If the package is not installed, it's assumed that the + package was imported from the current working directory. + """ + package_path = _find_package_path(import_name) + py_prefix = os.path.abspath(sys.prefix) + + # installed to the system + if _path_is_relative_to(pathlib.PurePath(package_path), py_prefix): + return py_prefix, package_path + + site_parent, site_folder = os.path.split(package_path) + + # installed to a virtualenv + if site_folder.lower() == "site-packages": + parent, folder = os.path.split(site_parent) + + # Windows (prefix/lib/site-packages) + if folder.lower() == "lib": + return parent, package_path + + # Unix (prefix/lib/pythonX.Y/site-packages) + if os.path.basename(parent).lower() == "lib": + return os.path.dirname(parent), package_path + + # something else (prefix/site-packages) + return site_parent, package_path + + # not installed + return None, package_path diff --git a/.venv/Lib/site-packages/flask/sessions.py b/.venv/Lib/site-packages/flask/sessions.py new file mode 100644 index 000000000..e5650d686 --- /dev/null +++ b/.venv/Lib/site-packages/flask/sessions.py @@ -0,0 +1,367 @@ +from __future__ import annotations + +import hashlib +import typing as t +from collections.abc import MutableMapping +from datetime import datetime +from datetime import timezone + +from itsdangerous import BadSignature +from itsdangerous import URLSafeTimedSerializer +from werkzeug.datastructures import CallbackDict + +from .json.tag import TaggedJSONSerializer + +if t.TYPE_CHECKING: # pragma: no cover + from .app import Flask + from .wrappers import Request, Response + + +class SessionMixin(MutableMapping): + """Expands a basic dictionary with session attributes.""" + + @property + def permanent(self) -> bool: + """This reflects the ``'_permanent'`` key in the dict.""" + return self.get("_permanent", False) + + @permanent.setter + def permanent(self, value: bool) -> None: + self["_permanent"] = bool(value) + + #: Some implementations can detect whether a session is newly + #: created, but that is not guaranteed. Use with caution. The mixin + # default is hard-coded ``False``. + new = False + + #: Some implementations can detect changes to the session and set + #: this when that happens. The mixin default is hard coded to + #: ``True``. + modified = True + + #: Some implementations can detect when session data is read or + #: written and set this when that happens. The mixin default is hard + #: coded to ``True``. + accessed = True + + +class SecureCookieSession(CallbackDict, SessionMixin): + """Base class for sessions based on signed cookies. + + This session backend will set the :attr:`modified` and + :attr:`accessed` attributes. It cannot reliably track whether a + session is new (vs. empty), so :attr:`new` remains hard coded to + ``False``. + """ + + #: When data is changed, this is set to ``True``. Only the session + #: dictionary itself is tracked; if the session contains mutable + #: data (for example a nested dict) then this must be set to + #: ``True`` manually when modifying that data. The session cookie + #: will only be written to the response if this is ``True``. + modified = False + + #: When data is read or written, this is set to ``True``. Used by + # :class:`.SecureCookieSessionInterface` to add a ``Vary: Cookie`` + #: header, which allows caching proxies to cache different pages for + #: different users. + accessed = False + + def __init__(self, initial: t.Any = None) -> None: + def on_update(self) -> None: + self.modified = True + self.accessed = True + + super().__init__(initial, on_update) + + def __getitem__(self, key: str) -> t.Any: + self.accessed = True + return super().__getitem__(key) + + def get(self, key: str, default: t.Any = None) -> t.Any: + self.accessed = True + return super().get(key, default) + + def setdefault(self, key: str, default: t.Any = None) -> t.Any: + self.accessed = True + return super().setdefault(key, default) + + +class NullSession(SecureCookieSession): + """Class used to generate nicer error messages if sessions are not + available. Will still allow read-only access to the empty session + but fail on setting. + """ + + def _fail(self, *args: t.Any, **kwargs: t.Any) -> t.NoReturn: + raise RuntimeError( + "The session is unavailable because no secret " + "key was set. Set the secret_key on the " + "application to something unique and secret." + ) + + __setitem__ = __delitem__ = clear = pop = popitem = update = setdefault = _fail # type: ignore # noqa: B950 + del _fail + + +class SessionInterface: + """The basic interface you have to implement in order to replace the + default session interface which uses werkzeug's securecookie + implementation. The only methods you have to implement are + :meth:`open_session` and :meth:`save_session`, the others have + useful defaults which you don't need to change. + + The session object returned by the :meth:`open_session` method has to + provide a dictionary like interface plus the properties and methods + from the :class:`SessionMixin`. We recommend just subclassing a dict + and adding that mixin:: + + class Session(dict, SessionMixin): + pass + + If :meth:`open_session` returns ``None`` Flask will call into + :meth:`make_null_session` to create a session that acts as replacement + if the session support cannot work because some requirement is not + fulfilled. The default :class:`NullSession` class that is created + will complain that the secret key was not set. + + To replace the session interface on an application all you have to do + is to assign :attr:`flask.Flask.session_interface`:: + + app = Flask(__name__) + app.session_interface = MySessionInterface() + + Multiple requests with the same session may be sent and handled + concurrently. When implementing a new session interface, consider + whether reads or writes to the backing store must be synchronized. + There is no guarantee on the order in which the session for each + request is opened or saved, it will occur in the order that requests + begin and end processing. + + .. versionadded:: 0.8 + """ + + #: :meth:`make_null_session` will look here for the class that should + #: be created when a null session is requested. Likewise the + #: :meth:`is_null_session` method will perform a typecheck against + #: this type. + null_session_class = NullSession + + #: A flag that indicates if the session interface is pickle based. + #: This can be used by Flask extensions to make a decision in regards + #: to how to deal with the session object. + #: + #: .. versionadded:: 0.10 + pickle_based = False + + def make_null_session(self, app: Flask) -> NullSession: + """Creates a null session which acts as a replacement object if the + real session support could not be loaded due to a configuration + error. This mainly aids the user experience because the job of the + null session is to still support lookup without complaining but + modifications are answered with a helpful error message of what + failed. + + This creates an instance of :attr:`null_session_class` by default. + """ + return self.null_session_class() + + def is_null_session(self, obj: object) -> bool: + """Checks if a given object is a null session. Null sessions are + not asked to be saved. + + This checks if the object is an instance of :attr:`null_session_class` + by default. + """ + return isinstance(obj, self.null_session_class) + + def get_cookie_name(self, app: Flask) -> str: + """The name of the session cookie. Uses``app.config["SESSION_COOKIE_NAME"]``.""" + return app.config["SESSION_COOKIE_NAME"] + + def get_cookie_domain(self, app: Flask) -> str | None: + """The value of the ``Domain`` parameter on the session cookie. If not set, + browsers will only send the cookie to the exact domain it was set from. + Otherwise, they will send it to any subdomain of the given value as well. + + Uses the :data:`SESSION_COOKIE_DOMAIN` config. + + .. versionchanged:: 2.3 + Not set by default, does not fall back to ``SERVER_NAME``. + """ + rv = app.config["SESSION_COOKIE_DOMAIN"] + return rv if rv else None + + def get_cookie_path(self, app: Flask) -> str: + """Returns the path for which the cookie should be valid. The + default implementation uses the value from the ``SESSION_COOKIE_PATH`` + config var if it's set, and falls back to ``APPLICATION_ROOT`` or + uses ``/`` if it's ``None``. + """ + return app.config["SESSION_COOKIE_PATH"] or app.config["APPLICATION_ROOT"] + + def get_cookie_httponly(self, app: Flask) -> bool: + """Returns True if the session cookie should be httponly. This + currently just returns the value of the ``SESSION_COOKIE_HTTPONLY`` + config var. + """ + return app.config["SESSION_COOKIE_HTTPONLY"] + + def get_cookie_secure(self, app: Flask) -> bool: + """Returns True if the cookie should be secure. This currently + just returns the value of the ``SESSION_COOKIE_SECURE`` setting. + """ + return app.config["SESSION_COOKIE_SECURE"] + + def get_cookie_samesite(self, app: Flask) -> str: + """Return ``'Strict'`` or ``'Lax'`` if the cookie should use the + ``SameSite`` attribute. This currently just returns the value of + the :data:`SESSION_COOKIE_SAMESITE` setting. + """ + return app.config["SESSION_COOKIE_SAMESITE"] + + def get_expiration_time(self, app: Flask, session: SessionMixin) -> datetime | None: + """A helper method that returns an expiration date for the session + or ``None`` if the session is linked to the browser session. The + default implementation returns now + the permanent session + lifetime configured on the application. + """ + if session.permanent: + return datetime.now(timezone.utc) + app.permanent_session_lifetime + return None + + def should_set_cookie(self, app: Flask, session: SessionMixin) -> bool: + """Used by session backends to determine if a ``Set-Cookie`` header + should be set for this session cookie for this response. If the session + has been modified, the cookie is set. If the session is permanent and + the ``SESSION_REFRESH_EACH_REQUEST`` config is true, the cookie is + always set. + + This check is usually skipped if the session was deleted. + + .. versionadded:: 0.11 + """ + + return session.modified or ( + session.permanent and app.config["SESSION_REFRESH_EACH_REQUEST"] + ) + + def open_session(self, app: Flask, request: Request) -> SessionMixin | None: + """This is called at the beginning of each request, after + pushing the request context, before matching the URL. + + This must return an object which implements a dictionary-like + interface as well as the :class:`SessionMixin` interface. + + This will return ``None`` to indicate that loading failed in + some way that is not immediately an error. The request + context will fall back to using :meth:`make_null_session` + in this case. + """ + raise NotImplementedError() + + def save_session( + self, app: Flask, session: SessionMixin, response: Response + ) -> None: + """This is called at the end of each request, after generating + a response, before removing the request context. It is skipped + if :meth:`is_null_session` returns ``True``. + """ + raise NotImplementedError() + + +session_json_serializer = TaggedJSONSerializer() + + +class SecureCookieSessionInterface(SessionInterface): + """The default session interface that stores sessions in signed cookies + through the :mod:`itsdangerous` module. + """ + + #: the salt that should be applied on top of the secret key for the + #: signing of cookie based sessions. + salt = "cookie-session" + #: the hash function to use for the signature. The default is sha1 + digest_method = staticmethod(hashlib.sha1) + #: the name of the itsdangerous supported key derivation. The default + #: is hmac. + key_derivation = "hmac" + #: A python serializer for the payload. The default is a compact + #: JSON derived serializer with support for some extra Python types + #: such as datetime objects or tuples. + serializer = session_json_serializer + session_class = SecureCookieSession + + def get_signing_serializer(self, app: Flask) -> URLSafeTimedSerializer | None: + if not app.secret_key: + return None + signer_kwargs = dict( + key_derivation=self.key_derivation, digest_method=self.digest_method + ) + return URLSafeTimedSerializer( + app.secret_key, + salt=self.salt, + serializer=self.serializer, + signer_kwargs=signer_kwargs, + ) + + def open_session(self, app: Flask, request: Request) -> SecureCookieSession | None: + s = self.get_signing_serializer(app) + if s is None: + return None + val = request.cookies.get(self.get_cookie_name(app)) + if not val: + return self.session_class() + max_age = int(app.permanent_session_lifetime.total_seconds()) + try: + data = s.loads(val, max_age=max_age) + return self.session_class(data) + except BadSignature: + return self.session_class() + + def save_session( + self, app: Flask, session: SessionMixin, response: Response + ) -> None: + name = self.get_cookie_name(app) + domain = self.get_cookie_domain(app) + path = self.get_cookie_path(app) + secure = self.get_cookie_secure(app) + samesite = self.get_cookie_samesite(app) + httponly = self.get_cookie_httponly(app) + + # Add a "Vary: Cookie" header if the session was accessed at all. + if session.accessed: + response.vary.add("Cookie") + + # If the session is modified to be empty, remove the cookie. + # If the session is empty, return without setting the cookie. + if not session: + if session.modified: + response.delete_cookie( + name, + domain=domain, + path=path, + secure=secure, + samesite=samesite, + httponly=httponly, + ) + response.vary.add("Cookie") + + return + + if not self.should_set_cookie(app, session): + return + + expires = self.get_expiration_time(app, session) + val = self.get_signing_serializer(app).dumps(dict(session)) # type: ignore + response.set_cookie( + name, + val, # type: ignore + expires=expires, + httponly=httponly, + domain=domain, + path=path, + secure=secure, + samesite=samesite, + ) + response.vary.add("Cookie") diff --git a/.venv/Lib/site-packages/flask/signals.py b/.venv/Lib/site-packages/flask/signals.py new file mode 100644 index 000000000..d79f21f93 --- /dev/null +++ b/.venv/Lib/site-packages/flask/signals.py @@ -0,0 +1,33 @@ +from __future__ import annotations + +import typing as t +import warnings + +from blinker import Namespace + +# This namespace is only for signals provided by Flask itself. +_signals = Namespace() + +template_rendered = _signals.signal("template-rendered") +before_render_template = _signals.signal("before-render-template") +request_started = _signals.signal("request-started") +request_finished = _signals.signal("request-finished") +request_tearing_down = _signals.signal("request-tearing-down") +got_request_exception = _signals.signal("got-request-exception") +appcontext_tearing_down = _signals.signal("appcontext-tearing-down") +appcontext_pushed = _signals.signal("appcontext-pushed") +appcontext_popped = _signals.signal("appcontext-popped") +message_flashed = _signals.signal("message-flashed") + + +def __getattr__(name: str) -> t.Any: + if name == "signals_available": + warnings.warn( + "The 'signals_available' attribute is deprecated and will be removed in" + " Flask 2.4. Signals are always available.", + DeprecationWarning, + stacklevel=2, + ) + return True + + raise AttributeError(name) diff --git a/.venv/Lib/site-packages/flask/templating.py b/.venv/Lib/site-packages/flask/templating.py new file mode 100644 index 000000000..769108f75 --- /dev/null +++ b/.venv/Lib/site-packages/flask/templating.py @@ -0,0 +1,220 @@ +from __future__ import annotations + +import typing as t + +from jinja2 import BaseLoader +from jinja2 import Environment as BaseEnvironment +from jinja2 import Template +from jinja2 import TemplateNotFound + +from .globals import _cv_app +from .globals import _cv_request +from .globals import current_app +from .globals import request +from .helpers import stream_with_context +from .signals import before_render_template +from .signals import template_rendered + +if t.TYPE_CHECKING: # pragma: no cover + from .app import Flask + from .scaffold import Scaffold + + +def _default_template_ctx_processor() -> dict[str, t.Any]: + """Default template context processor. Injects `request`, + `session` and `g`. + """ + appctx = _cv_app.get(None) + reqctx = _cv_request.get(None) + rv: dict[str, t.Any] = {} + if appctx is not None: + rv["g"] = appctx.g + if reqctx is not None: + rv["request"] = reqctx.request + rv["session"] = reqctx.session + return rv + + +class Environment(BaseEnvironment): + """Works like a regular Jinja2 environment but has some additional + knowledge of how Flask's blueprint works so that it can prepend the + name of the blueprint to referenced templates if necessary. + """ + + def __init__(self, app: Flask, **options: t.Any) -> None: + if "loader" not in options: + options["loader"] = app.create_global_jinja_loader() + BaseEnvironment.__init__(self, **options) + self.app = app + + +class DispatchingJinjaLoader(BaseLoader): + """A loader that looks for templates in the application and all + the blueprint folders. + """ + + def __init__(self, app: Flask) -> None: + self.app = app + + def get_source( # type: ignore + self, environment: Environment, template: str + ) -> tuple[str, str | None, t.Callable | None]: + if self.app.config["EXPLAIN_TEMPLATE_LOADING"]: + return self._get_source_explained(environment, template) + return self._get_source_fast(environment, template) + + def _get_source_explained( + self, environment: Environment, template: str + ) -> tuple[str, str | None, t.Callable | None]: + attempts = [] + rv: tuple[str, str | None, t.Callable[[], bool] | None] | None + trv: None | (tuple[str, str | None, t.Callable[[], bool] | None]) = None + + for srcobj, loader in self._iter_loaders(template): + try: + rv = loader.get_source(environment, template) + if trv is None: + trv = rv + except TemplateNotFound: + rv = None + attempts.append((loader, srcobj, rv)) + + from .debughelpers import explain_template_loading_attempts + + explain_template_loading_attempts(self.app, template, attempts) + + if trv is not None: + return trv + raise TemplateNotFound(template) + + def _get_source_fast( + self, environment: Environment, template: str + ) -> tuple[str, str | None, t.Callable | None]: + for _srcobj, loader in self._iter_loaders(template): + try: + return loader.get_source(environment, template) + except TemplateNotFound: + continue + raise TemplateNotFound(template) + + def _iter_loaders( + self, template: str + ) -> t.Generator[tuple[Scaffold, BaseLoader], None, None]: + loader = self.app.jinja_loader + if loader is not None: + yield self.app, loader + + for blueprint in self.app.iter_blueprints(): + loader = blueprint.jinja_loader + if loader is not None: + yield blueprint, loader + + def list_templates(self) -> list[str]: + result = set() + loader = self.app.jinja_loader + if loader is not None: + result.update(loader.list_templates()) + + for blueprint in self.app.iter_blueprints(): + loader = blueprint.jinja_loader + if loader is not None: + for template in loader.list_templates(): + result.add(template) + + return list(result) + + +def _render(app: Flask, template: Template, context: dict[str, t.Any]) -> str: + app.update_template_context(context) + before_render_template.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + rv = template.render(context) + template_rendered.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + return rv + + +def render_template( + template_name_or_list: str | Template | list[str | Template], + **context: t.Any, +) -> str: + """Render a template by name with the given context. + + :param template_name_or_list: The name of the template to render. If + a list is given, the first name to exist will be rendered. + :param context: The variables to make available in the template. + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.get_or_select_template(template_name_or_list) + return _render(app, template, context) + + +def render_template_string(source: str, **context: t.Any) -> str: + """Render a template from the given source string with the given + context. + + :param source: The source code of the template to render. + :param context: The variables to make available in the template. + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.from_string(source) + return _render(app, template, context) + + +def _stream( + app: Flask, template: Template, context: dict[str, t.Any] +) -> t.Iterator[str]: + app.update_template_context(context) + before_render_template.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + + def generate() -> t.Iterator[str]: + yield from template.generate(context) + template_rendered.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + + rv = generate() + + # If a request context is active, keep it while generating. + if request: + rv = stream_with_context(rv) + + return rv + + +def stream_template( + template_name_or_list: str | Template | list[str | Template], + **context: t.Any, +) -> t.Iterator[str]: + """Render a template by name with the given context as a stream. + This returns an iterator of strings, which can be used as a + streaming response from a view. + + :param template_name_or_list: The name of the template to render. If + a list is given, the first name to exist will be rendered. + :param context: The variables to make available in the template. + + .. versionadded:: 2.2 + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.get_or_select_template(template_name_or_list) + return _stream(app, template, context) + + +def stream_template_string(source: str, **context: t.Any) -> t.Iterator[str]: + """Render a template from the given source string with the given + context as a stream. This returns an iterator of strings, which can + be used as a streaming response from a view. + + :param source: The source code of the template to render. + :param context: The variables to make available in the template. + + .. versionadded:: 2.2 + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.from_string(source) + return _stream(app, template, context) diff --git a/.venv/Lib/site-packages/flask/testing.py b/.venv/Lib/site-packages/flask/testing.py new file mode 100644 index 000000000..773f1525e --- /dev/null +++ b/.venv/Lib/site-packages/flask/testing.py @@ -0,0 +1,282 @@ +from __future__ import annotations + +import typing as t +from contextlib import contextmanager +from contextlib import ExitStack +from copy import copy +from types import TracebackType +from urllib.parse import urlsplit + +import werkzeug.test +from click.testing import CliRunner +from werkzeug.test import Client +from werkzeug.wrappers import Request as BaseRequest + +from .cli import ScriptInfo +from .sessions import SessionMixin + +if t.TYPE_CHECKING: # pragma: no cover + from werkzeug.test import TestResponse + + from .app import Flask + + +class EnvironBuilder(werkzeug.test.EnvironBuilder): + """An :class:`~werkzeug.test.EnvironBuilder`, that takes defaults from the + application. + + :param app: The Flask application to configure the environment from. + :param path: URL path being requested. + :param base_url: Base URL where the app is being served, which + ``path`` is relative to. If not given, built from + :data:`PREFERRED_URL_SCHEME`, ``subdomain``, + :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`. + :param subdomain: Subdomain name to append to :data:`SERVER_NAME`. + :param url_scheme: Scheme to use instead of + :data:`PREFERRED_URL_SCHEME`. + :param json: If given, this is serialized as JSON and passed as + ``data``. Also defaults ``content_type`` to + ``application/json``. + :param args: other positional arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + :param kwargs: other keyword arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + """ + + def __init__( + self, + app: Flask, + path: str = "/", + base_url: str | None = None, + subdomain: str | None = None, + url_scheme: str | None = None, + *args: t.Any, + **kwargs: t.Any, + ) -> None: + assert not (base_url or subdomain or url_scheme) or ( + base_url is not None + ) != bool( + subdomain or url_scheme + ), 'Cannot pass "subdomain" or "url_scheme" with "base_url".' + + if base_url is None: + http_host = app.config.get("SERVER_NAME") or "localhost" + app_root = app.config["APPLICATION_ROOT"] + + if subdomain: + http_host = f"{subdomain}.{http_host}" + + if url_scheme is None: + url_scheme = app.config["PREFERRED_URL_SCHEME"] + + url = urlsplit(path) + base_url = ( + f"{url.scheme or url_scheme}://{url.netloc or http_host}" + f"/{app_root.lstrip('/')}" + ) + path = url.path + + if url.query: + sep = b"?" if isinstance(url.query, bytes) else "?" + path += sep + url.query + + self.app = app + super().__init__(path, base_url, *args, **kwargs) + + def json_dumps(self, obj: t.Any, **kwargs: t.Any) -> str: # type: ignore + """Serialize ``obj`` to a JSON-formatted string. + + The serialization will be configured according to the config associated + with this EnvironBuilder's ``app``. + """ + return self.app.json.dumps(obj, **kwargs) + + +class FlaskClient(Client): + """Works like a regular Werkzeug test client but has knowledge about + Flask's contexts to defer the cleanup of the request context until + the end of a ``with`` block. For general information about how to + use this class refer to :class:`werkzeug.test.Client`. + + .. versionchanged:: 0.12 + `app.test_client()` includes preset default environment, which can be + set after instantiation of the `app.test_client()` object in + `client.environ_base`. + + Basic usage is outlined in the :doc:`/testing` chapter. + """ + + application: Flask + + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + super().__init__(*args, **kwargs) + self.preserve_context = False + self._new_contexts: list[t.ContextManager[t.Any]] = [] + self._context_stack = ExitStack() + self.environ_base = { + "REMOTE_ADDR": "127.0.0.1", + "HTTP_USER_AGENT": f"werkzeug/{werkzeug.__version__}", + } + + @contextmanager + def session_transaction( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Generator[SessionMixin, None, None]: + """When used in combination with a ``with`` statement this opens a + session transaction. This can be used to modify the session that + the test client uses. Once the ``with`` block is left the session is + stored back. + + :: + + with client.session_transaction() as session: + session['value'] = 42 + + Internally this is implemented by going through a temporary test + request context and since session handling could depend on + request variables this function accepts the same arguments as + :meth:`~flask.Flask.test_request_context` which are directly + passed through. + """ + if self._cookies is None: + raise TypeError( + "Cookies are disabled. Create a client with 'use_cookies=True'." + ) + + app = self.application + ctx = app.test_request_context(*args, **kwargs) + self._add_cookies_to_wsgi(ctx.request.environ) + + with ctx: + sess = app.session_interface.open_session(app, ctx.request) + + if sess is None: + raise RuntimeError("Session backend did not open a session.") + + yield sess + resp = app.response_class() + + if app.session_interface.is_null_session(sess): + return + + with ctx: + app.session_interface.save_session(app, sess, resp) + + self._update_cookies_from_response( + ctx.request.host.partition(":")[0], + ctx.request.path, + resp.headers.getlist("Set-Cookie"), + ) + + def _copy_environ(self, other): + out = {**self.environ_base, **other} + + if self.preserve_context: + out["werkzeug.debug.preserve_context"] = self._new_contexts.append + + return out + + def _request_from_builder_args(self, args, kwargs): + kwargs["environ_base"] = self._copy_environ(kwargs.get("environ_base", {})) + builder = EnvironBuilder(self.application, *args, **kwargs) + + try: + return builder.get_request() + finally: + builder.close() + + def open( + self, + *args: t.Any, + buffered: bool = False, + follow_redirects: bool = False, + **kwargs: t.Any, + ) -> TestResponse: + if args and isinstance( + args[0], (werkzeug.test.EnvironBuilder, dict, BaseRequest) + ): + if isinstance(args[0], werkzeug.test.EnvironBuilder): + builder = copy(args[0]) + builder.environ_base = self._copy_environ(builder.environ_base or {}) + request = builder.get_request() + elif isinstance(args[0], dict): + request = EnvironBuilder.from_environ( + args[0], app=self.application, environ_base=self._copy_environ({}) + ).get_request() + else: + # isinstance(args[0], BaseRequest) + request = copy(args[0]) + request.environ = self._copy_environ(request.environ) + else: + # request is None + request = self._request_from_builder_args(args, kwargs) + + # Pop any previously preserved contexts. This prevents contexts + # from being preserved across redirects or multiple requests + # within a single block. + self._context_stack.close() + + response = super().open( + request, + buffered=buffered, + follow_redirects=follow_redirects, + ) + response.json_module = self.application.json # type: ignore[assignment] + + # Re-push contexts that were preserved during the request. + while self._new_contexts: + cm = self._new_contexts.pop() + self._context_stack.enter_context(cm) + + return response + + def __enter__(self) -> FlaskClient: + if self.preserve_context: + raise RuntimeError("Cannot nest client invocations") + self.preserve_context = True + return self + + def __exit__( + self, + exc_type: type | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.preserve_context = False + self._context_stack.close() + + +class FlaskCliRunner(CliRunner): + """A :class:`~click.testing.CliRunner` for testing a Flask app's + CLI commands. Typically created using + :meth:`~flask.Flask.test_cli_runner`. See :ref:`testing-cli`. + """ + + def __init__(self, app: Flask, **kwargs: t.Any) -> None: + self.app = app + super().__init__(**kwargs) + + def invoke( # type: ignore + self, cli: t.Any = None, args: t.Any = None, **kwargs: t.Any + ) -> t.Any: + """Invokes a CLI command in an isolated environment. See + :meth:`CliRunner.invoke ` for + full method documentation. See :ref:`testing-cli` for examples. + + If the ``obj`` argument is not given, passes an instance of + :class:`~flask.cli.ScriptInfo` that knows how to load the Flask + app being tested. + + :param cli: Command object to invoke. Default is the app's + :attr:`~flask.app.Flask.cli` group. + :param args: List of strings to invoke the command with. + + :return: a :class:`~click.testing.Result` object. + """ + if cli is None: + cli = self.app.cli # type: ignore + + if "obj" not in kwargs: + kwargs["obj"] = ScriptInfo(create_app=lambda: self.app) + + return super().invoke(cli, args, **kwargs) diff --git a/.venv/Lib/site-packages/flask/typing.py b/.venv/Lib/site-packages/flask/typing.py new file mode 100644 index 000000000..50aef7f46 --- /dev/null +++ b/.venv/Lib/site-packages/flask/typing.py @@ -0,0 +1,82 @@ +from __future__ import annotations + +import typing as t + +if t.TYPE_CHECKING: # pragma: no cover + from _typeshed.wsgi import WSGIApplication # noqa: F401 + from werkzeug.datastructures import Headers # noqa: F401 + from werkzeug.wrappers import Response # noqa: F401 + +# The possible types that are directly convertible or are a Response object. +ResponseValue = t.Union[ + "Response", + str, + bytes, + t.List[t.Any], + # Only dict is actually accepted, but Mapping allows for TypedDict. + t.Mapping[str, t.Any], + t.Iterator[str], + t.Iterator[bytes], +] + +# the possible types for an individual HTTP header +# This should be a Union, but mypy doesn't pass unless it's a TypeVar. +HeaderValue = t.Union[str, t.List[str], t.Tuple[str, ...]] + +# the possible types for HTTP headers +HeadersValue = t.Union[ + "Headers", + t.Mapping[str, HeaderValue], + t.Sequence[t.Tuple[str, HeaderValue]], +] + +# The possible types returned by a route function. +ResponseReturnValue = t.Union[ + ResponseValue, + t.Tuple[ResponseValue, HeadersValue], + t.Tuple[ResponseValue, int], + t.Tuple[ResponseValue, int, HeadersValue], + "WSGIApplication", +] + +# Allow any subclass of werkzeug.Response, such as the one from Flask, +# as a callback argument. Using werkzeug.Response directly makes a +# callback annotated with flask.Response fail type checking. +ResponseClass = t.TypeVar("ResponseClass", bound="Response") + +AppOrBlueprintKey = t.Optional[str] # The App key is None, whereas blueprints are named +AfterRequestCallable = t.Union[ + t.Callable[[ResponseClass], ResponseClass], + t.Callable[[ResponseClass], t.Awaitable[ResponseClass]], +] +BeforeFirstRequestCallable = t.Union[ + t.Callable[[], None], t.Callable[[], t.Awaitable[None]] +] +BeforeRequestCallable = t.Union[ + t.Callable[[], t.Optional[ResponseReturnValue]], + t.Callable[[], t.Awaitable[t.Optional[ResponseReturnValue]]], +] +ShellContextProcessorCallable = t.Callable[[], t.Dict[str, t.Any]] +TeardownCallable = t.Union[ + t.Callable[[t.Optional[BaseException]], None], + t.Callable[[t.Optional[BaseException]], t.Awaitable[None]], +] +TemplateContextProcessorCallable = t.Callable[[], t.Dict[str, t.Any]] +TemplateFilterCallable = t.Callable[..., t.Any] +TemplateGlobalCallable = t.Callable[..., t.Any] +TemplateTestCallable = t.Callable[..., bool] +URLDefaultCallable = t.Callable[[str, dict], None] +URLValuePreprocessorCallable = t.Callable[[t.Optional[str], t.Optional[dict]], None] + +# This should take Exception, but that either breaks typing the argument +# with a specific exception, or decorating multiple times with different +# exceptions (and using a union type on the argument). +# https://github.com/pallets/flask/issues/4095 +# https://github.com/pallets/flask/issues/4295 +# https://github.com/pallets/flask/issues/4297 +ErrorHandlerCallable = t.Callable[[t.Any], ResponseReturnValue] + +RouteCallable = t.Union[ + t.Callable[..., ResponseReturnValue], + t.Callable[..., t.Awaitable[ResponseReturnValue]], +] diff --git a/.venv/Lib/site-packages/flask/views.py b/.venv/Lib/site-packages/flask/views.py new file mode 100644 index 000000000..c7a2b621c --- /dev/null +++ b/.venv/Lib/site-packages/flask/views.py @@ -0,0 +1,190 @@ +from __future__ import annotations + +import typing as t + +from . import typing as ft +from .globals import current_app +from .globals import request + + +http_method_funcs = frozenset( + ["get", "post", "head", "options", "delete", "put", "trace", "patch"] +) + + +class View: + """Subclass this class and override :meth:`dispatch_request` to + create a generic class-based view. Call :meth:`as_view` to create a + view function that creates an instance of the class with the given + arguments and calls its ``dispatch_request`` method with any URL + variables. + + See :doc:`views` for a detailed guide. + + .. code-block:: python + + class Hello(View): + init_every_request = False + + def dispatch_request(self, name): + return f"Hello, {name}!" + + app.add_url_rule( + "/hello/", view_func=Hello.as_view("hello") + ) + + Set :attr:`methods` on the class to change what methods the view + accepts. + + Set :attr:`decorators` on the class to apply a list of decorators to + the generated view function. Decorators applied to the class itself + will not be applied to the generated view function! + + Set :attr:`init_every_request` to ``False`` for efficiency, unless + you need to store request-global data on ``self``. + """ + + #: The methods this view is registered for. Uses the same default + #: (``["GET", "HEAD", "OPTIONS"]``) as ``route`` and + #: ``add_url_rule`` by default. + methods: t.ClassVar[t.Collection[str] | None] = None + + #: Control whether the ``OPTIONS`` method is handled automatically. + #: Uses the same default (``True``) as ``route`` and + #: ``add_url_rule`` by default. + provide_automatic_options: t.ClassVar[bool | None] = None + + #: A list of decorators to apply, in order, to the generated view + #: function. Remember that ``@decorator`` syntax is applied bottom + #: to top, so the first decorator in the list would be the bottom + #: decorator. + #: + #: .. versionadded:: 0.8 + decorators: t.ClassVar[list[t.Callable]] = [] + + #: Create a new instance of this view class for every request by + #: default. If a view subclass sets this to ``False``, the same + #: instance is used for every request. + #: + #: A single instance is more efficient, especially if complex setup + #: is done during init. However, storing data on ``self`` is no + #: longer safe across requests, and :data:`~flask.g` should be used + #: instead. + #: + #: .. versionadded:: 2.2 + init_every_request: t.ClassVar[bool] = True + + def dispatch_request(self) -> ft.ResponseReturnValue: + """The actual view function behavior. Subclasses must override + this and return a valid response. Any variables from the URL + rule are passed as keyword arguments. + """ + raise NotImplementedError() + + @classmethod + def as_view( + cls, name: str, *class_args: t.Any, **class_kwargs: t.Any + ) -> ft.RouteCallable: + """Convert the class into a view function that can be registered + for a route. + + By default, the generated view will create a new instance of the + view class for every request and call its + :meth:`dispatch_request` method. If the view class sets + :attr:`init_every_request` to ``False``, the same instance will + be used for every request. + + Except for ``name``, all other arguments passed to this method + are forwarded to the view class ``__init__`` method. + + .. versionchanged:: 2.2 + Added the ``init_every_request`` class attribute. + """ + if cls.init_every_request: + + def view(**kwargs: t.Any) -> ft.ResponseReturnValue: + self = view.view_class( # type: ignore[attr-defined] + *class_args, **class_kwargs + ) + return current_app.ensure_sync(self.dispatch_request)(**kwargs) + + else: + self = cls(*class_args, **class_kwargs) + + def view(**kwargs: t.Any) -> ft.ResponseReturnValue: + return current_app.ensure_sync(self.dispatch_request)(**kwargs) + + if cls.decorators: + view.__name__ = name + view.__module__ = cls.__module__ + for decorator in cls.decorators: + view = decorator(view) + + # We attach the view class to the view function for two reasons: + # first of all it allows us to easily figure out what class-based + # view this thing came from, secondly it's also used for instantiating + # the view class so you can actually replace it with something else + # for testing purposes and debugging. + view.view_class = cls # type: ignore + view.__name__ = name + view.__doc__ = cls.__doc__ + view.__module__ = cls.__module__ + view.methods = cls.methods # type: ignore + view.provide_automatic_options = cls.provide_automatic_options # type: ignore + return view + + +class MethodView(View): + """Dispatches request methods to the corresponding instance methods. + For example, if you implement a ``get`` method, it will be used to + handle ``GET`` requests. + + This can be useful for defining a REST API. + + :attr:`methods` is automatically set based on the methods defined on + the class. + + See :doc:`views` for a detailed guide. + + .. code-block:: python + + class CounterAPI(MethodView): + def get(self): + return str(session.get("counter", 0)) + + def post(self): + session["counter"] = session.get("counter", 0) + 1 + return redirect(url_for("counter")) + + app.add_url_rule( + "/counter", view_func=CounterAPI.as_view("counter") + ) + """ + + def __init_subclass__(cls, **kwargs: t.Any) -> None: + super().__init_subclass__(**kwargs) + + if "methods" not in cls.__dict__: + methods = set() + + for base in cls.__bases__: + if getattr(base, "methods", None): + methods.update(base.methods) # type: ignore[attr-defined] + + for key in http_method_funcs: + if hasattr(cls, key): + methods.add(key.upper()) + + if methods: + cls.methods = methods + + def dispatch_request(self, **kwargs: t.Any) -> ft.ResponseReturnValue: + meth = getattr(self, request.method.lower(), None) + + # If the request method is HEAD and we don't have a handler for it + # retry with GET. + if meth is None and request.method == "HEAD": + meth = getattr(self, "get", None) + + assert meth is not None, f"Unimplemented method {request.method!r}" + return current_app.ensure_sync(meth)(**kwargs) diff --git a/.venv/Lib/site-packages/flask/wrappers.py b/.venv/Lib/site-packages/flask/wrappers.py new file mode 100644 index 000000000..ef7aa38c0 --- /dev/null +++ b/.venv/Lib/site-packages/flask/wrappers.py @@ -0,0 +1,173 @@ +from __future__ import annotations + +import typing as t + +from werkzeug.exceptions import BadRequest +from werkzeug.wrappers import Request as RequestBase +from werkzeug.wrappers import Response as ResponseBase + +from . import json +from .globals import current_app +from .helpers import _split_blueprint_path + +if t.TYPE_CHECKING: # pragma: no cover + from werkzeug.routing import Rule + + +class Request(RequestBase): + """The request object used by default in Flask. Remembers the + matched endpoint and view arguments. + + It is what ends up as :class:`~flask.request`. If you want to replace + the request object used you can subclass this and set + :attr:`~flask.Flask.request_class` to your subclass. + + The request object is a :class:`~werkzeug.wrappers.Request` subclass and + provides all of the attributes Werkzeug defines plus a few Flask + specific ones. + """ + + json_module: t.Any = json + + #: The internal URL rule that matched the request. This can be + #: useful to inspect which methods are allowed for the URL from + #: a before/after handler (``request.url_rule.methods``) etc. + #: Though if the request's method was invalid for the URL rule, + #: the valid list is available in ``routing_exception.valid_methods`` + #: instead (an attribute of the Werkzeug exception + #: :exc:`~werkzeug.exceptions.MethodNotAllowed`) + #: because the request was never internally bound. + #: + #: .. versionadded:: 0.6 + url_rule: Rule | None = None + + #: A dict of view arguments that matched the request. If an exception + #: happened when matching, this will be ``None``. + view_args: dict[str, t.Any] | None = None + + #: If matching the URL failed, this is the exception that will be + #: raised / was raised as part of the request handling. This is + #: usually a :exc:`~werkzeug.exceptions.NotFound` exception or + #: something similar. + routing_exception: Exception | None = None + + @property + def max_content_length(self) -> int | None: # type: ignore + """Read-only view of the ``MAX_CONTENT_LENGTH`` config key.""" + if current_app: + return current_app.config["MAX_CONTENT_LENGTH"] + else: + return None + + @property + def endpoint(self) -> str | None: + """The endpoint that matched the request URL. + + This will be ``None`` if matching failed or has not been + performed yet. + + This in combination with :attr:`view_args` can be used to + reconstruct the same URL or a modified URL. + """ + if self.url_rule is not None: + return self.url_rule.endpoint + + return None + + @property + def blueprint(self) -> str | None: + """The registered name of the current blueprint. + + This will be ``None`` if the endpoint is not part of a + blueprint, or if URL matching failed or has not been performed + yet. + + This does not necessarily match the name the blueprint was + created with. It may have been nested, or registered with a + different name. + """ + endpoint = self.endpoint + + if endpoint is not None and "." in endpoint: + return endpoint.rpartition(".")[0] + + return None + + @property + def blueprints(self) -> list[str]: + """The registered names of the current blueprint upwards through + parent blueprints. + + This will be an empty list if there is no current blueprint, or + if URL matching failed. + + .. versionadded:: 2.0.1 + """ + name = self.blueprint + + if name is None: + return [] + + return _split_blueprint_path(name) + + def _load_form_data(self) -> None: + super()._load_form_data() + + # In debug mode we're replacing the files multidict with an ad-hoc + # subclass that raises a different error for key errors. + if ( + current_app + and current_app.debug + and self.mimetype != "multipart/form-data" + and not self.files + ): + from .debughelpers import attach_enctype_error_multidict + + attach_enctype_error_multidict(self) + + def on_json_loading_failed(self, e: ValueError | None) -> t.Any: + try: + return super().on_json_loading_failed(e) + except BadRequest as e: + if current_app and current_app.debug: + raise + + raise BadRequest() from e + + +class Response(ResponseBase): + """The response object that is used by default in Flask. Works like the + response object from Werkzeug but is set to have an HTML mimetype by + default. Quite often you don't have to create this object yourself because + :meth:`~flask.Flask.make_response` will take care of that for you. + + If you want to replace the response object used you can subclass this and + set :attr:`~flask.Flask.response_class` to your subclass. + + .. versionchanged:: 1.0 + JSON support is added to the response, like the request. This is useful + when testing to get the test client response data as JSON. + + .. versionchanged:: 1.0 + + Added :attr:`max_cookie_size`. + """ + + default_mimetype: str | None = "text/html" + + json_module = json + + autocorrect_location_header = False + + @property + def max_cookie_size(self) -> int: # type: ignore + """Read-only view of the :data:`MAX_COOKIE_SIZE` config key. + + See :attr:`~werkzeug.wrappers.Response.max_cookie_size` in + Werkzeug's docs. + """ + if current_app: + return current_app.config["MAX_COOKIE_SIZE"] + + # return Werkzeug's default when not in an app context + return super().max_cookie_size diff --git a/.venv/Lib/site-packages/flask_login/__about__.py b/.venv/Lib/site-packages/flask_login/__about__.py new file mode 100644 index 000000000..1eb282623 --- /dev/null +++ b/.venv/Lib/site-packages/flask_login/__about__.py @@ -0,0 +1,10 @@ +__title__ = "Flask-Login" +__description__ = "User session management for Flask" +__url__ = "https://github.com/maxcountryman/flask-login" +__version_info__ = ("0", "6", "2") +__version__ = ".".join(__version_info__) +__author__ = "Matthew Frazier" +__author_email__ = "leafstormrush@gmail.com" +__maintainer__ = "Max Countryman" +__license__ = "MIT" +__copyright__ = "(c) 2011 by Matthew Frazier" diff --git a/.venv/Lib/site-packages/flask_login/__init__.py b/.venv/Lib/site-packages/flask_login/__init__.py new file mode 100644 index 000000000..fbe9c3e77 --- /dev/null +++ b/.venv/Lib/site-packages/flask_login/__init__.py @@ -0,0 +1,94 @@ +from .__about__ import __version__ +from .config import AUTH_HEADER_NAME +from .config import COOKIE_DURATION +from .config import COOKIE_HTTPONLY +from .config import COOKIE_NAME +from .config import COOKIE_SECURE +from .config import ID_ATTRIBUTE +from .config import LOGIN_MESSAGE +from .config import LOGIN_MESSAGE_CATEGORY +from .config import REFRESH_MESSAGE +from .config import REFRESH_MESSAGE_CATEGORY +from .login_manager import LoginManager +from .mixins import AnonymousUserMixin +from .mixins import UserMixin +from .signals import session_protected +from .signals import user_accessed +from .signals import user_loaded_from_cookie +from .signals import user_loaded_from_request +from .signals import user_logged_in +from .signals import user_logged_out +from .signals import user_login_confirmed +from .signals import user_needs_refresh +from .signals import user_unauthorized +from .test_client import FlaskLoginClient +from .utils import confirm_login +from .utils import current_user +from .utils import decode_cookie +from .utils import encode_cookie +from .utils import fresh_login_required +from .utils import login_fresh +from .utils import login_remembered +from .utils import login_required +from .utils import login_url +from .utils import login_user +from .utils import logout_user +from .utils import make_next_param +from .utils import set_login_view + +__all__ = [ + "__version__", + "AUTH_HEADER_NAME", + "COOKIE_DURATION", + "COOKIE_HTTPONLY", + "COOKIE_NAME", + "COOKIE_SECURE", + "ID_ATTRIBUTE", + "LOGIN_MESSAGE", + "LOGIN_MESSAGE_CATEGORY", + "REFRESH_MESSAGE", + "REFRESH_MESSAGE_CATEGORY", + "LoginManager", + "AnonymousUserMixin", + "UserMixin", + "session_protected", + "user_accessed", + "user_loaded_from_cookie", + "user_loaded_from_request", + "user_logged_in", + "user_logged_out", + "user_login_confirmed", + "user_needs_refresh", + "user_unauthorized", + "FlaskLoginClient", + "confirm_login", + "current_user", + "decode_cookie", + "encode_cookie", + "fresh_login_required", + "login_fresh", + "login_remembered", + "login_required", + "login_url", + "login_user", + "logout_user", + "make_next_param", + "set_login_view", +] + + +def __getattr__(name): + if name == "user_loaded_from_header": + import warnings + from .signals import _user_loaded_from_header + + warnings.warn( + "'user_loaded_from_header' is deprecated and will be" + " removed in Flask-Login 0.7. Use" + " 'user_loaded_from_request' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _user_loaded_from_header + + raise AttributeError(name) diff --git a/.venv/Lib/site-packages/flask_login/__pycache__/__about__.cpython-311.pyc b/.venv/Lib/site-packages/flask_login/__pycache__/__about__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d3d0d6e924e234aed3b97df64c2b4a4f8d2d6c19 GIT binary patch literal 689 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

Q%OMdsI%Vy-sNJGBzMp=A;LTPhS*2d2z~ zr5+^FnCCh|S{n<@IJ6|jL@A8!3FW~xWSWz_3k>jj&8zQ5H@f` zP3PbaoV5_T51D(13F|__o&mx-clrY?+0Foq>HWN&72mSc*+b!NJA5DgcIbZ+n3+Ce7{%jI-GGIQQSvl?cTL=?zZ$ZU!fzMi9ZoHVf=|W6EtcI zY0-DADeIQbn<$TV3D%^hgCj_=eQf^#xj)i*l?5DXOMlXG(QnzAO2VUZBgz;j@p>jV zRzwJTfrsM8&x>Hf0;Z)%^Gg`zpNop&gh&EK&ofTx&9Y%sBe^+n>O>NBtny~6LLx3Z zv+>d(WYF3wsfL3jq6(ET?!O+1Mo~L2i7WA25ME&TD%CL};SY`;8|6Ws{Ge773dz^> z1y%5&C07k0ws12l-V&n$Th6f_mSQCGayG(p^;7v?VM4#4MoCX2W56aoiyvu{z$pS3 z021`lS?f;&$vO45Z#0>xRu5mHOwR$_2Yt+3P_|J>b~^*8T2 zIcL+CoZVUdYXZ9rxH)GHrQ2MP+YV+NPbrS4WbKxwQK*T6Xte47tJeYUVf<5;5HR&h zS<2H{XTitztLaXNvVj>i@wOKVUk zF|?!^L?fUk64)xeN#arjL?W^1x$q)TjnmCRcZfzuh$Qslz%s)N%P1^KN=}hZ0!0Dp z0w{M5^^BUh&D?0UUdA}nAE_^~-kA_1XI z{1he5&$MRZ_g3)xti$!t(X#Dmx!9?dw8DUM^ZyjLIqf$$WvUE-K7AHY-D?FFa(V}JL?pR_~NU!UzcPuGO!jsgs zM@Sq?nYQcgke)|wmsZ?s2a<)NNiOLzS_=9_4n4oQY{ck#@W<9-Ei=|;F1=97h;^>8f}{hCKIIZ%ib>?iP$ z3=~3AR@12I+Pb+VrZOs78T$=o6t~QVw`YnkU&qH)=34I9k_QZ>+RWnx&hH5S2avAL zMVLAPCQVEnLVTS}I^sygr%33NJ_}C}GabRJA;MvNGD8qis!-s=dTE;W%&$k1%X~St z!=!{SLuf?74@aoV7>NZ^D)iEzT&T?&<*y)tv>r)_BU&mx2~PuS>S8<^jjxks3~LiI zD=}V>BE%^7Gra`OAx*wW3(AWh)oPj3*fDk9Ad1vN&}(`z#M$v)))G{qZV)B-MY4k_ z0V|RxgNcXLu6KqCQDsA36cjS&3!BqRGn!X(?0x5JE-DS}fN@{i7B~w^Tf&0!br+SR zS4=&l67x<13_D&0%Xljc+mBoTbLuOj{u#wJb#6a@HSacLSr`fB1zh2!jPgUXcuT9W zJ1Es{eqEFbnkp5;^B5=yL~?)7h^SsOMjE7VuENius+-iuxjAw+&CT&JyQJGi{Yt=c zLm8U1HF`Thy{dgOu$p7X{kkJq3cxNa(qRkwvY0YQD{LiXi3msZx_fC zEriThCk$oC8-7Klk@};x995TdFw$5+Sse`&s2L=+V$0yU%X zlB6&u6d&fvFUuc3_!K{M-RMH(MM(lBX-a#c8H{Hnmg8%1RWSn~xhA19p4^xyj*&hx z&WoUb@qkIw&^ zrBMQ;HAn{u93?;^Tq4^ySE(wWIV;L!?T|=ZNGA!9(?}YkR93VkSIhjP>J-AWL~=D? zSM3>A$v>m?gOna#5|u(jNSL6?+1y~-R?cnYqZ=)kjCQ#(>R%vRVhJw`w)q(6Y=!;& z-Vcvo?bf>bFFAl;6WG%vpVzf3b-n4ztgG(r@i)fhrjcKbp31mRE3VVK zT&44p6l-20>Jho-ytydf*z!6rI5{*@Y8tIXNEe@L^1%tNOajszF${idA^<38=^ENS>?v@?hrM3u-EE{<*5VHDj;8(q9tT!gkYC~(NzA(%*O!K$d zE6q0z9+-tV^B9f>EUcFwT3ELdRF&EnNd&slTG|J#;|k&vq_m?Km7KRh@$|@!p5K*j zPkuwXEl0Is)o+BsXRg!2Sc8Ifc~O>fnHNCIr#S%F8T0FST4E0EaCYQf@KN^O*&#^T9u3|QNWy0s?PDM z19k-VQetC zH8~>%=NYw5$k0(&Vd6kpij(fe6xO_s&6saqTO&;!&5ji8k62t<2}hZ7_N`d5vEOVO zB?=St$;{ZIDpe&k++Zv=l(z#nx=q7hF3JBQ5~u?J_iEq=8l?*&ysH>%lXXUMS`9`Ai->-KR*t$}N2rU8|LT;lU&OEq|FkTGCRo zLyKWO(chZ6C-4t)<^6*nAp1vp5k_BO-j~;_M`C3q*;jbFq4(b0CQ})zFVE-?G>mLf z8?CV(SpsJq0+XHD)av@vBh*TH;zcR}bn=XjEjFN%#N%%d{GW1XAi#%-Qv zn<``UVz8SC`-^BV5nE}5_*n=;=BRQ;^K&q-MKT+u}&(zO4V7#|Nc6uq*+YT8RJ@r{uonru z1Q2MFc*4I&ppwAL1ek;zBaHZ*bcjH~-*lKBnU9E^2zxr4m={Z$qa`H*&++m+@(`aHRo0-r7Y z;-=hoA=7q2X}j=bUy`oDd>139??j<>F{7S?IQ9AlJ5k6RMLH3?Qe+xchCf1K`YdF! zLw6tjE*nnF7NKF=iMcLVU}gMW<^2Zg_AB`Ju{Kc<3$ssh8_*Vqf+WL=5d_^$tUnp; zE?vcDR@Fac&q02-&ca}RGn(oZ_?>p_n1`ycZ$~-{I+4x+fSFt%{33x%1STlds(P}Q zD1hQkTLf}7rWO`47gOAEVlJmp0L;ARa(i>0e(c_yZni_L!(a!H|3te8XLbO!klX`z zX+2+yHT{}3N77%DhLQ@qQPn*)8{OBi&rV&(Si-VUOw|Oi*0Yd&Wt0eMbOx`8R&^y( z({rx85lB(+TRux+HhM7md%6poGxB>2)g34yT4ZHg5;sOomeLc`U!m9AkJ^|I(Ctm1 zV7z%?+c%K$4Jp2%^c2|CTb4I#()cU&64{WIy}_pe&7RG>P0(+3ZgkgU+-o6Jm^IZu zv?O(_1p6bXRCXnGi@~^S!aNq{lGvU)Ls?o$#q0QN=SEoz$y_?^lDcCtT2=)sNhs2{ zX1&O9(Gzy!;@uE~RWG8byI+`A_VvEA9fs9fO5-oACE6I9zs#1&9UJx~ zmd|D1+s3+MPuY^~T8Vh;`aX+WT-?9Md#E(`MX0*TB*~r1RHZajzOCrZA@Ik!UNmqpI^qwFB#JUi@qOg1?CUil0`e`um^!Q=waDoW+Qev zf-^Z-#{_PG6qBdKn;& z_66)ml>!ZHy+UF>Zs+tX3nG^H<1vXW`yvfE*Q#%p&Yz$`!q8$k0^3j8p!94_mFd4s zmnBMI)v9Z^RqA_6f=_Q_S|D{`VB)$jvU*QBZoRd4vs?45>` zb?XJ<<8J}v`MBchlwAX~qB<$>JO8M@ZMUMLuKP=?%~$(t4q%tF)zp5Cy{k>wg#F%x z(l(x9dTGXSQgNJ=9Vf9O>ZW8-~II1Ur+q} z2bn_`l|vW*ZhiaEcXzE^ji1)CTCvPrGx4Z}f4A#Fo6>S*voh;%d+49o_D}r$OvZm& z@t@wbZQ8PRjY{1hy^9GJe`wo}#q5m#gyKJ;#<#y;^)ruLcK~-uX=B^|u}_X>{Nsv$ zeA9*(@z8T*+jHa-A>)})JQK2GqEue$dV2-5hrK+HW(fqzz-<|H4G>8FDoR&jlA*d} zDN2Ri>IM0_MeQlM=u}H#k79{bu}QX+O{lnKktzi1HE2!JPg51}=anzZCUE8wRM{Zi zMH%*+tY3+$l%?QLl*aZft60uh*DR7UlFrf*UlE*j4Nm!y6Eh77c9>C#t=q2H9fxHlH=%@)Cd7C4EaCBJD4s-ah)6#>^wu3kG&_}tYi zv(u;9Ny!Rn1f}IF;i|!U(iw^Q3)CPS5yVkHX%q3%s|0=sFdJ~IypTB#*mjdjiYxdB zj^HupTotkO6NBSUA`!2$Tas%z>uP*8P?^^|N$TY6?0gE_TA#D6;GkE|ax+1Ns@#dO zCh0XiZw#7wl6JnOgk`@*JPHSD!J{5|niS7)#xtULM$)#dx8b38Y}-4Q@g7#Zhtu}Y zYg?4s{h8VWO6`HPHS4K=bK~tFzVSo3bL^8TCXC^ zH;>?ih}*l%xt;Bs)Awip?8TqHxFtTA&2)?@9b?-KV{*e7ya}7@Z@ij*b*t}Zqv=<{ zpza-i=lK0|8DGER>wj=v_Ko4r_787P-EaQ!%p-5N;vLvZWW4(n?>^bPFY9mLTm$#G z-@IMdE!TBFYN0JNb>!Ws8`zwLqv77Uch22^e#@3==vNy0Wp?lM?E_c&UdG#9rogt% z{RGm5ncrh$gwxi;_%!9tWNn8U0rjLxnY&K5|dtr~J7TmCB1 zR>4JH+h^i8y3St2Z*1jt_!P9$k8Nho0NovPf=;9b>@!jdb)S)b42ZoABwqtnQXhU) zLZ_V_247hxJ(B-S+d}ovDd0~CP*z69MLVaYKSIRDh?#hGfvTRwEz%R-BMQEYY@p!! zuC2;U{h(4msENC5PXK#`E@a$YS-v0Gxs1C5l$D-hzN;S4M$KU+W`?)@!w-&S{D&0( zAqXLlPxf>@YU);+j%1pSDNV;Vt&hBeig)C}wNH|=_e92fLh+seg3OyPBu^(FLnQS2 z&4!qC9>a>z(yJ`_j3t@!uBJ8|JVC%mdJ%W5?C_Iy#dZhozm%;!^G{h*6{Sl_DI8>C zgKV3TXsru}g_~8~jA^L(L(r-|B>gK&P|17>h2hRsB_d0)a5N$PDWXl|{w4+JL(bxh z$Ni6yWTW@7$Hg)OWcoZC-b_(HTrz|^-jlNV-ti7S z^zPsG?tifGbDQklpYfhlSc-2nuJ_T7qH#U-t;TiVHyhXTlbVgBrDVElBUv${4wRj# z^@V|wx@b7qyv!ffBC%Q+AG6O{dL5A)eUBZPyhG~W)6kGtJwG(vbQnt=n!vU%@L(|G z8&iB^<%i~xcSzAj;pDd)g#pw{?$#u#)-EVQ0VBgL%$Y62Owv*lD>fU6QZ?MOg=mz{ zn6tSKPP%S7!eY}hU>+7JSR@1lYhJnOf{Q>)ieDJGaLep5TZ;}JSh!dlO3Eu~OgK~; ziqg?yE&_hQ+{ZIaHOciA8;9EW7N#dpp9@``e*XIOwb`5%-d@J?nNkB*&rCb2&!EKo zOFY6=hNPPLR1;!GW&Sbmb)=70sC#2_PMn0rJ~=uIKw|;jMO9p$$3rotl|T6OH$-V$ zNPd^waW%cSB)j@?|J6Qa_{78EXSau+&AP|Fv{vlHnLq$U!T#tYL2xnS<|)UZ?CQq- zsJZK1*Ve^P8ZymCmFA=A^E;mA`_tQ=ZrRhlb>q{s^1uXcrV8=fUVf`N;~iGK!!od zc$?=w6o zqFfHaktD}P{=$4}H!A(cIKk1PCF4GJn&8~8x4Gkr_4jhdtrLAX z{C3A}JfJ1GQ_er--YcS}l=}}W1n!RehwgRDI`@k8C2pOzlIRY+!ux=+W=&P6Tu?Oa zsmfGU%JFf{2XMuGq`TwPj~@hTXQVsGmTM~JQ&U$iPoAGCb#6U3IeYFmmII|3)DP6; z@Ie`~H%$B5O=*nwm75%WE+Bv2GJ&nVF(Co1s49<^=F>i@!#L)~RB?q`G{3Tzz}8_p z*`a+HXjK0y5Du!Shp_pjcygQ%RORe!`7Bq3Z@XYyVj@>5#Oa$KIooPDxeQ}e#3>0e z=ODLXJQl_001|L*(dPpKK2_uw%uTX`C32BUU}f>V5my2v@~Kny`OE;NKGX zcLe^Lz^4HCJkpvf401NSkFfL!1zJS5lTZX*sDWvnY+#7#qT<$#n*@2Ajg5tZ7c9aX-ado~AArrv;$j|?kUw&#z z2~5j=IJ(X#{xj)w>2o{&j(Z#LY{)$)K8t7kGm3vEeGX1LZ^wJr-uFLfRk{ynI*uqE zN3`aA?rPjze&3pL^(n4Cvat`Lng=6JhZ>4XWQjn>v4O^3_U{;#^@4|A^^CI*k5z3<77-1$YT|sY^sQ+} z`j0d)X9=7m@Sgy{I*LY5=OnsW78BQ*icz{FMEYA4@%SP0(U4t4GPcC^ZHElv9yn28fMUU+zuDF4w9B?JKUN&Xyz(wvCe4k-Q@tjwBqsg7u5hqwVn3yX+TSf z(kko&hLi)l4woJJgAQ7CjD@w1Q44giY-yy_IvB0A}VF zZEwI@fd<;E3DZGy6+P;p-b2;tpl8SqhMCT(#-cUBxXx9tdO(ZeCSxt}3-Nsxg zOgASRQPsYgT28`U)yy*v+4(FH6cez}pX?!wgy0cujY`(Kxt8BirT#IbJ zOG9?JKG}R{xn9|Pmka5VIn!M(O=$~xnKRwxdNC|>rn_9pBQj^Yv*uz^OO_jw&3Bd? zkj;0wkRF*c-C1)*s5i^)m(6#U8FK~RuHNpM4?i!Dw3*TS-M<&oA`)*XLi>K zu~Hf#9`b-HKxy5VO0+^C#Gf%050RxvNc{swp;E+CXZGyFUlgRS?eXr+?#%4$d_C^# z>m@KY9?n`j8XB zivNvs+X5D4LP<)oNJ_PoRDcGrfezkCX*6U3&quI)+CY+24`2fw*f3y&9oUGa-6pAC zD+DlV^#F`nVbCX1jeO53yJX+6of7NSVa#N0t{0fQWLuQ$7M(YXIicJ6LXPICBTQkt z4%g>hri(1q^HgMAi^JR$`Zqa~FOE;S3$`O!(HjMt5nL~V2;H5#CKtlhv*r?=kUKJp ze;-0{9)RC=2tXN(J58Rb$(bkQiBb)6nw#giLw{|YJC#PQdHSL`XU~~ww?Lg~x5zRy z?Wynsof|(}D2&e(h0AO+m!4Rn&Qf~Ho=bCE(D8zqSu__YPtT*qMh-PTkw+u&iNZ=X zVspdH2z!Z^625sRd}I`L>;bSwUJNAG#WqYy_nX9lQYNe98g7vT?xZBg6o$UWkcoFG z7J+Fsjxvg1S4Y?xQ&6k)L96^`+5jF#Hd2i{H!I--EC$Q&nzY#T8-~jc@i7$dxXw!6 zE%MTEtLO$k0Vn<2?_Mu<%EVxi@0f*2nM8XmIifVY?I} z&_?wE;ns4(BDd6KawBk+EGuJbvUD`*>a(^rtD8bFd#)&`KCZhQtwgwK=hywU#xHWjR^3kPdgURQE$;!-?O6*E4fO~d!c6bn(ahOmMR(_Qu?!F8TW{9S4MlD{3;siSDFWHRll9s_BMACQeE7~!YZqT= zeKl3lc7uOtyI%%KsQ>mA4-tYn&PI?l(nK1mHAq898fqd9)j~lHQ$iDrg^-00;yv2F z8tDYmY*PCS=K{=aQ`hqXkAemN|%b(}8cj>d0Q<{dxno3$E9-kTHDt(&0|!WDRew zp`RlQtZ1E841GaHF*=Lajr@m1tiz@KZ;>cli7!#g`-{TvulwcDp-TtfBC27>Nj#2? z%DXQHDTVdFRT@T4Xr$Fc-Hx)ORoccx|jxBdbyKmq8-f!N#dGnrr z7exWV_~o~!YA=G&Yc?5=sgZJKa|m^jid0TVb#8~_Pyk`>7|bVQF4_s;KySR_9A%0c zIEM8n@D9gL(3d$i!3_B_gA>fKFEcd3oc3jgCz!l1b9#aq@n!N8Ou?5KnP5hJnZg8f z#+MnLV2bL@_h=`kirXj`d&90H$9a)0rH*Mssp3{dH)}Pl<~5@wj8wB}wUWB2r~vO0 zv!1V-=Dvn6V|y6vq;>5gkKnJHm|CqkIMNJQX6$ODj#Y1_X(&x=&m>w4t1Z#MSfzP_ zcL}C@9Ujx4;30Tfxt$$>=%OPi&iw$Wh%BoC73t_( z?uhGMT)~Wkp-x%Bu@2=K{4;b6o=(n-mqS+gy?q;5&=})!gf6G_J1!UA^3qL;i99^L z%(5g8GeTHIt-~cB^OB@dNyQCtJZNMGm*-OoQ{X_W31 z?iHlR6iZiqjuH+|4Qj!K6yC7i;erKfDb;-)A7DKf^7uoA7@AR|UXW>C^0QF@kn1Ny zlb4ZwBKBgNmPNEm)54z?55>5z)G#gYvZF&{;pj!G)eJ?a zg~m5tRF-SlQXmvrCJET}4%_}Qh&DQ%j@t3%zowV%>E%;C{XEWoulU)Y#UI6fARw;3 z4I^>!G@a>3QRMnRC>#;~Wuni-+ZdW%w)v&Mh0L!hM_6!$1v|KK29D8IF7AngcnYIP z2&)*6mq$}CJXE~cD0!@vWXi7YXV9I)lhCueGIF36- zH|)#Lt7z)^`VaSiy5HveJW9@Y7dwl+tdq#QiF`W-(6wy0*eUjIJISJ(EVknSWpBJJ zz9`za9ys$QcfMq!G=Lx8d|7%?vR6t@cEinX*eG)W+;Fm+Zg!J_0?J6;XPsyE(wdWA zchl=ON&$23qwb^5qu!R2T6I&aHc9|?eW5FNYxN^v!r3(sM0Kc8l65JVs<8T_d)=*~D>(Ib>t^>hOaKtbZmtswveB3_~GCoPM7_NUg zPEoN*T_;XZ$uRX;tp&AM=k*#&rzmxOH=;B?z!?`+p;2i0+_EF2<3yE3sB9)of3^c^U!k2J_%Cn1$eXMAlWX~t z9Z)ib$5H!u;nA6gXZ{^o8kyJT%d0t~eRK$^Yk%(R=qMq@Bzhwh-U_t6wR^9S?oFt`A zU{fm3G|u#@YBSHH)Fk16I7)GEzY7l{4#hhrk?46oiU`km^Xn+8p2CmR?oA$!>O&O;UV_6iZLCC9?7p7WhY>EARo)C<_&e0Ns<>n8=_@94nX z+(zZApNN9+wjc|#m=>n#*OeBRT+=R*>h83A$usR?bx+#6|>A+Im zbRDbvQLmq_XY~N;!Ra8Y*P$Mo4zYSY>J8HktR6%?JRN5BP&%^IINiwV4e6$(=ya6T z!>Bh;H=`br8`CXIt<$Zn-h}#&=^d;dO}8zzPq(vrGwL1F9jxAhdgpYfD7XZrQEq)r zcpszv5Py7|-YNIXJ6;o~yYSnF-)_16HDP*}+<~%39*}q9oFsSQXt&&ra*rIBC7jzU z@5a$Sc@N6{@?Mk&eVD#*ZQ!{5rr%siAMeJv?dFoY*c`B8mzRsuAB}Gp1so|vyKg6kD?LzUkkh5k^5Z=d`5Anyh zN#O%=0!`Mi5?d@ie|66s6vt4ikTrSa62*5b?8 zzX=>qCzj^q#0j+T#whY>qFqU z#FDg}xSq}?D+=i<_tc`1|4vF2&`=B6zx$<%yGk^9+0lcOW&N2g|97=6X)Gu{nj_Dcd{C`a~V2hQARDABYt<&Vi}I;7%gp4DZPYu8QBFg}NIvsL>or zlG=rzN&}~d@r1e`=jgmfl{I0zU5M-`28XcU32&@?JW^~wT53P4w;$yvi=LrxVV8eE z8*dABV3-Zm9^7P6u3?%>=-Lg}4R?;%&DaWV+3jR4wYA{huo%s}kA7v3Q()e3XPWj3 zIbvXA+b5_{53dNacT!jpuDM?kR>WMLc~uZDd(C>T!K?{F!375QIeSs4?Uk$Gnq=+9 z{E3W%>A7gqEZ&wDQdqLm+;wTzLH=3BG*=ZB{E-A-WiwKCp16d~vB6&R39RIPES-sL zM#0))D+>IPT3Sx0lBrz!x`gGBS2M&eoVodW;Li_9!x>`{$i||wbCr41|8pxq?ZI@Z zO(-fpPVb60p(RtP301<$n7`svHBcy5@k8e%ayeD)rJL(tCfPHps#&$-SzJmaE8%2z z2^2GzkGh8*_f&kGG;9f}`{+?0UtgLB2eb%{6~*6fuBgMfcnE*m+bC#7dA*Txr}S3? zzZ$sfzWdKgor8Mk;Omif|E(Qc!RW0gZyzlM_vyiX+k#lvUvAy`_MiOnPd2_^YCWX4 z9$Fv!`s=M=D=v8>)uJ2-ulv@0+islw`s=TM?-K$c-QRiV#NFPHwc^fWrJcw0oyR_T zx#T~k`%lqxZRN<0^)Nlq#ttsDsoCyk~#Jg`%<<&XQ~N9GnzomYLhwvwT7lJN_!iQJIz)qSWPOC53rBX zqTR76Pt972EG4ce zGZ}!w8P=S794|PDKWzoYn(+G;p`rEGE2U769_m>e-3qnbx>ySB)B3ZjNsY zZtpqq_UJp~cSk=O-|RYC>^fRz7u-VkQ{}GR_6uJ`I&MF9Titl#-J!erj|!i>^xKPn zyQkQBwiKDrBNN5IL^-&l=-I(Fp2foG2rUe@I3`dbfV6?%2RFH9DX6Z3Fex~6UCmM= zCS3imjC0O2na(*7gpz=R88>ovxSCQ{`X%MsGPu%&BXmy6B*3Z+R?$PLdDd1&QRG_f zz-Nb^;cUhp6LYTy7IV2}ZD??C)lW54z7Ypwu1dX@ zOQ<=GfSpQe7a*p-+Jr{5Hl%A4A0tP#Gt^ym7*}7$pEigB61GtYMDO{#HvL`2?x#xr zA>BVjQm(Tc=_m#|zJQP&Dg}4x!CghqE;g4H4{=zMX3*S-k=cwsk9Yq8apx|GYpw#o zu45+MPLXoMle2^m@Py~G^|qS(ymmBFK-)E_!&`9CBFHgQnRmA;$~J7`&m0O+k<0mx zWgp&80-bF)aI|4VK<0V$(wA$s9eHKQyKJq$`G0HaE6E$cI-0VwyhJiCC93kio zky>RZQ<5hzs+04&MDUCI?tY)vKz|n-LO&jBK9-^58A+}CP z#1YS?I5MAQLIrDr8j-99SaXZn6$K#7-Wu?@0(qYR?4k#sMr(jxOeQHg1uHSjUczLZ z1ct{DSW{31%z7cYZ(BvA8_dy4bFkNV12A*Ya9rYc-Z&XauT+zO$S_ZehUT5PwkjyT zO>)JhzTq@`e@;nX=eAcOnad~AtmA~=YBobDI;SokW48}6d(r-8Q_2}C)?_cnhcylpG7aPQ0vX4wP7|WRCBR=n4>LiX%3$bcawZ#rQ#cf< z87&=h=ANB(43hQ2c$wLciAwvU_+kpO+oNUGT+F2&fhiYD$zO|EEt@}2n?j9|*9?@Hmtesq2eRX21p--%MgGkU`_#fA%?KCO>jSQ{(1?7r7>aI@uLInsJ(`mXEamSXplrS2#7?kBh1 zLhGR~1y`%@AE;P63p5|vacha&1Vzt24nELZYxAH6nJRqMkHV>{s%ZK_Q=5DZ-4F|6&QgVT^Z%-lZL_-osdD7z7|-NEgddljttnX}M8p;)=afdyDP|uOS$zdJ{2Bf<6$N9La0gZv zmQb|)?SsEOSnPiMHy2CMVLdv$_CmR->plOwkz&(evFXBZp8Jn4d>Skr8P|`D7hk-v zdE~;{^JRY%*#mpGn%dv&+1RN!4XpdNqCFeFQnXi(_OAP37T=bOkv+x0o^r5p{Rzg3 zV^c{RaucY|mfJ}%60p8ot1AeXaguMEi(KR`Cl(ZPv`CGuiu|gksgo(+$DLJI@eOam zYe#!B!+!;jAY^d3$Nl2Q+BwGIqX$dULmw##9&W=HUsttIT7t=w+&?phju6n4%s z1$?l;8xtOMm96pd>;l1IS{?9($E8=Yc}ZK$=F>9sA~12xAq&4JJ9im&KZlMfjX`8c zY}ORD0q8iJ(q`}kU4!X{Lh;UYu!vc#CK@fC+Hsm{zWCFnsSv)Z+Kx0@k%o76i4j@x2mJGcfxFUNSe!LIS4hnA?H=*{N zZgUs2z1P*g4J8p?(uQVbSaH;|I2E#z&Lw8;G-Zr4M8ObxVeK3;Bf|)wpbv~z2L51v zZOolD6gxW3DPhjJ z)v=|7dWAHtM)4kL4{Li*ZQuB)99<(IWt;smU|ymRG^2VBQl#QWt>VTUsgpRI_+2~7 zR3pSu>e-VKVSxnA+H3LQN|U9wXAld^W@K&kh&fNv64}96)(PpsiRuSAwH$0OX(5{% zk`O`iPzR=BO_e%Ja#Z}lrxTs%qZY$IN3u>DS{-tqZHm{J+64<#C5F_9yZ(J9{IY_Ye{99Oxnusnfx*h z0fTjfi)Uz77~xdX9WXv%saKj=VAXVA@};g427?iipxXlG>Zt@wT2;J^Tku0OqyB(y z6O{){2h%l0q*4itzJovQ86Y?~pAHKlfDF;wdb{PFU93`$w5;dvhezI6xFz3tLGOA( z?>boukLcl%Qg~DkkFGse?%e$^pId*vKZz>eL`!u-V!Uf_2_NAcl$mX_+(G% z;PFp#rGq1-wvkWsr5)p6y2aMB;{BGLU;5pLyWa8_+Ygl*`-_eJUjvM{>;XVRJ65r^ zqo>^R(%&8}w!DP>OSh{n3d5u=dcUoG+v{rTK)m7WZ8sjFz(c*@ZPY#8_dL&RdY<{z zQ}T@Jp3$ObbjuUfJ#BY_di(cF?N90LPyJ2ZXTiS?7Cqx7&$#XxN2MH$tRK;c!9P2G z=wzSpd0+iVz5DaWnn%3u|Lpamp2Rh4BjwIOSeSt@d%VG^j&Bh9w^;>O1+~TQrn8~? z8s{w3v+FxPSp!G#r29KQS%dunJZxaC3J*8z0MsIa?8({Sj1yciyT$@8uxl)c1`6~7 z*x6_zGhiqC?dQIQPJXAof<8A}T@o%^Zb^G2<}#TJY;(>|LHH=(>~{?XtnqEwg0W^> zwEzoruLGc}U;R@ina6Et3i%swf)JjPvrI^n2b{DGMQ4~|vf-+DteUF8S^`wcN@NdZ zr2I0w+msy=6f(DL2<-s7DA!V2&Oia`Mf8+Oa`h6`&Qmc(1&MQYhKgAfQ?W3UOk8@p zm$S={G`ZB5=pk~-s!LR4sF0~hqkt7oqD^JaaGGEWY76YAMM7#CqzI)NW&1hdS_RQbxEJe@i(X%ks{L!}--pm&L z`>~gM4p^dW*L%IiU<~^f`~okKYzp=3q5fj1{|isE?rFcXQ|~xh>KM{HhCXd6dd5ng zG2JtU$`_u9C3;GpVcj!a^b9kp@-6;^k3j+Cl8Ge5&5fH^_O(!z5gR0P9@v~b?P!ae zWtK@~_b)i4khSWaZPl(c*#rLeuKtK|B?I072b_ORH;tis35+l;7MCUs%b&1x7W|4( zOWMd@0kFBwIUI;mRVZ5q%fg6fa=zw(Wva@?6HuVEEIE%d-kYaGa_HEYvc?J2!2Ema z5|7)c*KzaT<4+qy0j*gtbo?R3x8-Ta1mC%$?|Qnl>luC5GbPWny64%Vx$|j;61Fy) zET$yLw)|O*YwY!!NZYzFk8ts80p|pe7zN2)iL}SC(ST#&M~5>tnFX97SjEC@MoLl& zW(}l(k>sT18Bm9RmJp;lLk0w9bjP~nwiYvn$hA*^38^2L1_S6L%`MFw_-MiqQuIdh z=`u)togCw=F@R6@c6x#{#SkI0p;<`6ROT!PY;k)8VHQE^beiH1ka=T<-(9(uKqiSY zG{lof$cT6r;g7fq38M7%4lct--^;z=>>9=ZJV>An29V5pLgx{+km%OF*pPLO&XdID zE%W|^MC93Lu^l*ja|tp{U`c3<&Ze9;ng=04O%}*_C>i_NLlj+soQKe+X|WFkLYg4D z2@9!>I00Qd;ho(zj9T*vA_O0>0e~I!?2GY{#pCgn#Z+>U%qpxtnp4mjnPbETNK53y zU`B@(u}R1>vwzs&XojIh7~$Z$H&O|(h7eq#6ai9Q3+e0}Zxy*dFc0S?+b}3~h{b^N z8So>bEo5UEYngK35_6CN)B$h|x6Cjyq!00=Beqx<3@a2?BeD$X{@L+!&z+f=Idx`o z_~iKLDQ@Orh-6Tb<;F}LBWh+W5Ck`@{G^2p3|BKJDIS+5vRFU%*?AEL_w0qorG-2U z2QWQ&0DxQ?Id^`NB0ux#)WRag^cei-kw4<7<3=cXWo0G4@_0O}E(}hcAH@392KO@O z=K$hm;L!o&$pPYu0jt4*!zX5E`Yj$kJvH?rtmbnsPMtY7F$q7o`98*`$~ET1U?P(7 zfrJEz6-L0MTPkXwVxDj`!WkRYiv)=CnUv|}Y?m$;PxNnBb@DowF^1H}jKiYK8i zXcgZTggf!;Ay&|6^pdp3UE^VsZ)6tvUOnKHy7A-4z5z@<5qI8)40A#IS7_+#H35ka zH&5L8VKI0J`@j3KJ~(`DaCCEUv^e&1Y4CzRcmb!&p~kJIZoMfE%eC(KR`V{sx&L1C zQ=83Cm70&~&BuzNV-&J!dF#15FWl|^#8YZ{T5ox}6g;5^PtYSL#d7oEw{YjdyGKgR zhxO*eAMYzR4}Wq11?{0>il*gmO%)^iZoiCz_5crRsWjjZT>RNAI!^vCx{1Pz7~StriGnY$uWdPy1ASIaUUdgI5B>^b|OUOfo`;PgiSz~ZA!N;8Asc1Gp z1gVGIRJaD2{zIA@g2Nj5GY!iLY6wXKrU>Pzz;YCly0+;xN=q1`75S~G#z+gHrH0Wn zYN$(zwCN#dkg2v+_^+scHZp?9csm;!BX$+qQNs`I2Ei5jo`KyDZ#nm_5mw__?40O` zQ*)rgRHF%Tj2slu`C+ilXp`r?AU@ApI;kusKskx~*{D}6JDp(05Ys`k&Q&vOsvoA7 zkwgy;K{h%cBc|!$df%Lx|F5zMZSc$wMqMl2hEFR5k+u0yV=BAwe^X_@{7b+P+@Ku>?Y6=6-p zs2yIEo7-+3x!qE1?%UXbg7%QHBbB@^1{bhK$pN2-I!+!CK0gpWdCdL!kcg70c6FWT zMQ$lmr?)(eQtBJHqmRh)Br2rYAG0a;pcj2{6qaJAvz>OuZgX)mKLGTx@YOV0b|%R@ z+|^T!(mTN?l03vUU%@52c+!We6@)+3LP4y$a*v}EkGS7*^1k|{(`j9GKvjEnRaE!> zp>`f|o#?RmHde<-8jQKNL;h0ndRATX1MlcsBmLl$lcLGh4wg0V>;Vh&$k zEF)Kvr(`Co$7DG3#CdL*(KEJY44adTLuN!BP&OJmL74lpGuu|VS^ZJhG*Upvwjc_P$L_YrBrgWqz9l1aL@*6w#x;=W` z(N8*lyQ@@p8aZxAm<#RKLx&-r%8e~XnCyjOBkhPQHFfEYF}?A~@7-pV;!BOA2zVVn z@(|X*Jkhv%SFX)of(aHk}6zBXAP0Q1$ ztO;BG&XT`N_jhdz9&dL!*#4ea4DQCh6>0<7?}ZL;h7OlPkLjVuilN88h&0~3Q4Dn5 zr;r>co~_%04^1-SZJ^>L9&*+3(hu>+w;Q6v$!)b#5Rs~9Ng?xY`mOy!!k$d$bO}5> zB<3VIBkDKad~SZ=C{{<1qT}%A&EP9ZwI6S*xHHO1#m7IvQ%T%a>K2u2{Hrc?FOKb> zO0w_3Sn*>b?J-;iY3o~WB}?_4dVS~G$QQxL&7-$QZnyo_u3zoC>o0X2);kXW=0GX< zlpcKQUT|bHI8q9Z>OqQ$KFF2CL5#5f9hFD@hPTbie(S+8sEN4q8aspVi*&vk(&H&^)J!NSHwI0T%7rhBts)NoFyMtf-qrW zV$Q%@s;ckc=8Bhp)aQjrPSI!Oe!2vwtNo*qMwSd(`YKK1G%A?JaO=(Nz3}eM z@b2QC$A5D{f8um0d`1tSL2%w5M$ij_rn&R&_%GudZKY^TkH+pr2REaGAA3sCC-mqO zA1Cza(RzH1qiYin&N6Wso8?8k{g0hxC+*pMwmxzx)%e102=)(4 zoC^itbGzxQ?mKQQSu27IpkjH}1R*b|(VPv~7x3|}?7;^h7){kvhv%)txLU|h`LP?8 zzYuh=wu1NwaZvMJo^$*n(h$F!*D>awSgn5vLUmvmc_=x?YV3Pa`i}-!k~tX1hine` zjFAG9n?D+>=jOr&`pDB>iP=^nR!Xgddh6hN{Z@EaDJsTdr@zJc$x>38kamcRZDWv#GQ*os7f-P`VV z6eEw9B9H5l$Jaeuf$-~rn}N0Avd8Kfic;N2x*58>EtFx9-_p^z1GN zL%%ro^JA|+ee>y}r~N^Ww&d0jdhS#RcJc4zxQ}X71ryaVky&B*9?T=Bk~yx+ocgWO z##5x=si6NVVg^nVe3psN4b=aDxBmqZu#FQi7`gMxUtWCYB4Wv+%q!W$JDRS|p`gat!hG2wKy1x290#tly_~J6( zLs~Vh8+8mtr9P#RUn!A6wCvx~S;mC_xwA0d2hgo8NyG=qNwLhgIyS2$bna!Lv*_H*!tSDT zFAIB%&i%g7U3Bhcp}FYX%fkMmb1w@WMd$wA&OF%8zM|mR%g#ewy)X0>oqJi>Q*`bR zj_bj8%0jH@+_wWlW9Ry6v2y@>DH7Ks@wL#lFC-pA;+&({)grcS3(g|mMCYucFDUlF z;b0bBl8C^9vltUSVjqyTS%iZkG61cj>#*3kEjWvLv6D_(#gJbd7Pkdk*)k}0ZVOf+ zi@kJg6;ooDh>u#G#R)$(Y85SRaSV+`_, + HTTP ``OPTIONS`` requests are exempt from login checks. + + :param func: The view function to decorate. + :type func: function + """ + + @wraps(func) + def decorated_view(*args, **kwargs): + if request.method in EXEMPT_METHODS or current_app.config.get("LOGIN_DISABLED"): + pass + elif not current_user.is_authenticated: + return current_app.login_manager.unauthorized() + + # flask 1.x compatibility + # current_app.ensure_sync is only available in Flask >= 2.0 + if callable(getattr(current_app, "ensure_sync", None)): + return current_app.ensure_sync(func)(*args, **kwargs) + return func(*args, **kwargs) + + return decorated_view + + +def fresh_login_required(func): + """ + If you decorate a view with this, it will ensure that the current user's + login is fresh - i.e. their session was not restored from a 'remember me' + cookie. Sensitive operations, like changing a password or e-mail, should + be protected with this, to impede the efforts of cookie thieves. + + If the user is not authenticated, :meth:`LoginManager.unauthorized` is + called as normal. If they are authenticated, but their session is not + fresh, it will call :meth:`LoginManager.needs_refresh` instead. (In that + case, you will need to provide a :attr:`LoginManager.refresh_view`.) + + Behaves identically to the :func:`login_required` decorator with respect + to configuration variables. + + .. Note :: + + Per `W3 guidelines for CORS preflight requests + `_, + HTTP ``OPTIONS`` requests are exempt from login checks. + + :param func: The view function to decorate. + :type func: function + """ + + @wraps(func) + def decorated_view(*args, **kwargs): + if request.method in EXEMPT_METHODS or current_app.config.get("LOGIN_DISABLED"): + pass + elif not current_user.is_authenticated: + return current_app.login_manager.unauthorized() + elif not login_fresh(): + return current_app.login_manager.needs_refresh() + try: + # current_app.ensure_sync available in Flask >= 2.0 + return current_app.ensure_sync(func)(*args, **kwargs) + except AttributeError: # pragma: no cover + return func(*args, **kwargs) + + return decorated_view + + +def set_login_view(login_view, blueprint=None): + """ + Sets the login view for the app or blueprint. If a blueprint is passed, + the login view is set for this blueprint on ``blueprint_login_views``. + + :param login_view: The user object to log in. + :type login_view: str + :param blueprint: The blueprint which this login view should be set on. + Defaults to ``None``. + :type blueprint: object + """ + + num_login_views = len(current_app.login_manager.blueprint_login_views) + if blueprint is not None or num_login_views != 0: + + (current_app.login_manager.blueprint_login_views[blueprint.name]) = login_view + + if ( + current_app.login_manager.login_view is not None + and None not in current_app.login_manager.blueprint_login_views + ): + + ( + current_app.login_manager.blueprint_login_views[None] + ) = current_app.login_manager.login_view + + current_app.login_manager.login_view = None + else: + current_app.login_manager.login_view = login_view + + +def _get_user(): + if has_request_context(): + if "_login_user" not in g: + current_app.login_manager._load_user() + + return g._login_user + + return None + + +def _cookie_digest(payload, key=None): + key = _secret_key(key) + + return hmac.new(key, payload.encode("utf-8"), sha512).hexdigest() + + +def _get_remote_addr(): + address = request.headers.get("X-Forwarded-For", request.remote_addr) + if address is not None: + # An 'X-Forwarded-For' header includes a comma separated list of the + # addresses, the first address being the actual remote address. + address = address.encode("utf-8").split(b",")[0].strip() + return address + + +def _create_identifier(): + user_agent = request.headers.get("User-Agent") + if user_agent is not None: + user_agent = user_agent.encode("utf-8") + base = f"{_get_remote_addr()}|{user_agent}" + if str is bytes: + base = str(base, "utf-8", errors="replace") # pragma: no cover + h = sha512() + h.update(base.encode("utf8")) + return h.hexdigest() + + +def _user_context_processor(): + return dict(current_user=_get_user()) + + +def _secret_key(key=None): + if key is None: + key = current_app.config["SECRET_KEY"] + + if isinstance(key, str): # pragma: no cover + key = key.encode("latin1") # ensure bytes + + return key diff --git a/.venv/Lib/site-packages/flask_sqlalchemy/__init__.py b/.venv/Lib/site-packages/flask_sqlalchemy/__init__.py new file mode 100644 index 000000000..7d38ee684 --- /dev/null +++ b/.venv/Lib/site-packages/flask_sqlalchemy/__init__.py @@ -0,0 +1,46 @@ +from __future__ import annotations + +import typing as t + +from .extension import SQLAlchemy + +__version__ = "3.0.3" + +__all__ = [ + "SQLAlchemy", +] + +_deprecated_map = { + "Model": ".model.Model", + "DefaultMeta": ".model.DefaultMeta", + "Pagination": ".pagination.Pagination", + "BaseQuery": ".query.Query", + "get_debug_queries": ".record_queries.get_recorded_queries", + "SignallingSession": ".session.Session", + "before_models_committed": ".track_modifications.before_models_committed", + "models_committed": ".track_modifications.models_committed", +} + + +def __getattr__(name: str) -> t.Any: + import importlib + import warnings + + if name in _deprecated_map: + path = _deprecated_map[name] + import_path, _, new_name = path.rpartition(".") + action = "moved and renamed" + + if new_name == name: + action = "moved" + + warnings.warn( + f"'{name}' has been {action} to '{path[1:]}'. The top-level import is" + " deprecated and will be removed in Flask-SQLAlchemy 3.1.", + DeprecationWarning, + stacklevel=2, + ) + mod = importlib.import_module(import_path, __name__) + return getattr(mod, new_name) + + raise AttributeError(name) diff --git a/.venv/Lib/site-packages/flask_sqlalchemy/__pycache__/__init__.cpython-311.pyc b/.venv/Lib/site-packages/flask_sqlalchemy/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..136595adf095291ef90c7b6bc5f8e15941b022f1 GIT binary patch literal 1931 zcmZ`)(Qn&C7(Y99;@C~nv}@P0sWWU<$)JX<4@0P;DvYs*wJe@R3Wi}x`)2-f230-tdk~HpgrsXDQG-k5bNOQ^Qmkf)3{jVUa%o<^Th^B{7JIc^&Rhu&4RXw@Auhlte}HhimUyAhu8 z(NUAlyi-Sb)ws!R36LFMa*fQGli&J zuXef9{DNI|EyuCl>LE{h`UR9||MS_YetlY#(&16o4#6|xOFUJ4-Lvq@I8RZW{TNVGr@!iz7~7=Sv37)ibSH1XF>I$ zcAw?iK4K++rm&UlVfI>0iDY};ea2@y;>2Suh2(pEO{JMU*}nkD;IV#ia~(SfUnBUtEmJdb8#EPi|H z4x)-_^7Wb~O);fggvl~H%dB0l6ZAgD9xkLYKLb3%4L?{a`4(BC+96Qn2qslrbT`7H zNvjf(NU$6Mf7JADIaqw}?b0U!!a?b}Rkq7k$@7uB;MH*jmEsM#jmnd=zCU@ZPCRT| zPRUq7?n>!~T`mPSL6bh)7psbb(jwnKGq~ee@x%3oY1*z$Ow;gJsb-po%P~z{U=%p< z;4fy@Kq#GRcWWpOu6@XV`zh_4FWRXwRv+iaHpyP@!nzcmpLj6y)6CA)?)fWw=dbK4 z`ntApb5jZP7uJ*e+TaFxq@8JNXTqVg>(};`{%Ob6cBGU(QBfn?IA7#h4mVbL|H#@zTonB8o z&JAw_o7Z=9<9oUBwle-i9oam!tB&odV{K{d8Cx(YNbv#YSR40q!|x4~m1>%cb@l?W z)5rWW(j-~+nYO4vXc~P^kjo$A=%0XZ=n6YF=5wi-CVT(btd}?%-`-yVzR26JGIO9z z$KrYiUuG_UV1j$hbP|Ffgy5C-$+`~)+TFSjUT&YP``Mv2t&;?DzLO9&aV^zRLH2Ao qI1vt94D;v0(V1}cweZ|rI5N}8rw7FjU}i1X85t7Jb-)Wu#Pwg+IwU{< literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask_sqlalchemy/__pycache__/cli.cpython-311.pyc b/.venv/Lib/site-packages/flask_sqlalchemy/__pycache__/cli.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9772fccade7a951aea82a7c55e0f9f7a213f4a3c GIT binary patch literal 1153 zcmZ`&%}*3D6mMrgSOz~3B+*3T=*4W}j^N1}K;~qk7jGoQ3nyQ@tU!VsNPu2>xdZ@XZuBZ?^ID8#cEYun=1YzD>*&xX0#9Qb-@{zY~+PpuhLEd17+i#Y8g zQ4}kpf;f`XdhR!bV3G1jlB9XTR6|5N{WS2^BdNqiN4b+xbI$Kv-O(8spyTa280$#w zi`4;hM<_nsHPI@ddx2I^eK!My>iP^L^=#L=hTenuxjRLxcm=Isni&Vr3WglA%U|!Y zg+MAM7BV^gvEJ@j*@FWiZxJ00hmQgru>iwIh3U?)Sd3)`n)#Csef3 zyg}fl1<#8}$UF~xmOGN-P-?CnXNOFUl^;kZWcenk231my6Bf?|N{GKm7MLuX+uFJ)b!(?Ll!Xezc z<2?2WmlN*Z!ef9=o&(iF8}@XkeH?u`x^|`Acjh&DQ~T%L)>Nbxtrl}aQJ#wL+#Qbj%&x@At1#mh!mj9F;Fe^$42&0 zyZ7wdBkkT&>*}Tf`NjHHXpdZPkK6@#-|gwPJ>8nx>>p@Nz05wpwb^&9bz7W(?QnAr z29eixPilMKd;>lfypPa@pXOCF38IA*t2Ad=HJKR*LjQkrh{3v37>818a5f=^A)xC= l&Vbs=V2n4>`Hh3^2O8MuwjXGC<6zs$7x3{d^dDs|{R@42HirNJ literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask_sqlalchemy/__pycache__/extension.cpython-311.pyc b/.venv/Lib/site-packages/flask_sqlalchemy/__pycache__/extension.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4847019a40852417e7dad92892868ac220fe4849 GIT binary patch literal 42019 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

-lr1m0r3k;no{%A{ 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask_sqlalchemy/__pycache__/model.cpython-311.pyc b/.venv/Lib/site-packages/flask_sqlalchemy/__pycache__/model.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cc12ee77367895fed81633d10f3463a5d0e4e3ca GIT binary patch literal 10148 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask_sqlalchemy/__pycache__/pagination.cpython-311.pyc b/.venv/Lib/site-packages/flask_sqlalchemy/__pycache__/pagination.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ef091931cf821368f1f8601b7447244db326fc68 GIT binary patch literal 14786 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±mamumd)NFUtNxLP!J_|Q$$xOoe{|J?HEm!fX9%ZPlhAz=Hwu6{oZKHxKxVGHr_L zLLv~+ES1OYO8jHO47&@UdTSS)<$3DnuT_NTxNx$2(CoS;yPv7KdQ6+Kby(N-)O}R* zP>;z!0yM0TQ>d)id7dwG{VUebI@i8Z{gk;aE7s3C*R@jpm|M%$N>gk13TOFLTv-PX uUt{C)b5{R_xpmId&V$^I#nQs(RQpA(>E!_RY%G?pd``7rY|zBE=Dz{68_tvf literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask_sqlalchemy/__pycache__/query.cpython-311.pyc b/.venv/Lib/site-packages/flask_sqlalchemy/__pycache__/query.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..672bd5dd4e2cbce506b4254fc6bcb8d607e6e1a2 GIT binary patch literal 4893 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 J7Ypvw{{bNdp#%T` literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask_sqlalchemy/__pycache__/table.cpython-311.pyc b/.venv/Lib/site-packages/flask_sqlalchemy/__pycache__/table.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f2a869c74b161828f39b19d44883d5f890f39600 GIT binary patch literal 1893 zcma)6&2L*p5Z`@Yes*k{rb(M#s;KJ42fK(PLWlz5LxLRYBGALqvVLz9Uh@3x>^=vK za>&6FK?>YZIdDJ-3RN%sDL!zB_Ed=zH&^C>a$;tm?bNaftevsUdjvk7z&{_sN@O)i)%_F2D%C4IO*J`-AuHl z2LYa!z;f$oYrB&Q?d^YNwzygSUfS256j@KE+CgP#O_HK8|*2)F6-P_G3U) zJ4z%wvH}K1q>WBbhNAga!qtB5L(!_; z>vn4odRa%tJZaVsMS9qLFK#teoQYbOhx>e2sOAouV}3lr#QJwLgrwf>YoD<=jWfo+ zxRT>kpDtiij4`fbGFm0Y@`*hLfoQ)iG9K}apRXuhe;oWuE~B}Q>Kj02fCK*@ex2w1Ubw{eM7S^UcneI_1PR|DvFIAh zW@`O9FyGRLaKSQ!VKU~sd2gmUqPz6S`jOrzF*&k-qTf)wybWUDs#@Ary{?c3h&kM5 z@#`XEAyii}Hfx>ZOLDmb0jZaO{0(LGNb%;^?pKA=!teg(ck4s{?hg)-{QK3Lu{mRs zu9ot``EW#DIP8FCYO-$lM-N@tdeJIhftc_V`QvEVC?N6XShmOqUpI zccNZ`e3`L>9#1A3nrXjtC}h&%k-<|}Cdh>%Nf@hAY3hunc`XMJYbudor0O>y0NV6- z=6Zu*R3ckVFecGLu5J zjM(h-;Hd&^B;Ho-W&LiP?#kOJlrCNeZ7HrdF626}_55LkC-WfD-bAR(J(}7z53O-$ zZhGz=@9Vk$N?w*%WgSGsSRDfy*_6^Va(g)cJtb?y>Gzb}7*4-4QXBruH}Y;#fMt=K Q+&}&38Lt1eL}?=Y2X9rPpa1{> literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/flask_sqlalchemy/__pycache__/track_modifications.cpython-311.pyc b/.venv/Lib/site-packages/flask_sqlalchemy/__pycache__/track_modifications.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..88a9bcf5e9cd8ac97de1749a5f369bf184cc26a1 GIT binary patch literal 4109 zcmd5<-ESMm5#KxR9giQP6zYSvY<<{LEHegWw05LgimeFxu$$4(Vq^+=eV)xzn}le2Lsp7Kn6|DdI%DNj zA#Z5EGC&lVS8|$OR8rbE%vX^37d2gn4L)zn6;v&&CsKu6E@K#)`gv?cOBaZicvV6D zy0hkGudWOiNN!k96^fcF*TkRHw!BM4q8XbcPw{*quchjz15Xy=2Va(Z@g+zfA_Jyw zTd&(4@~*6TECB)xw!YR>{wv=RhSP_i)41=uAO5fJC%L{LbOi7DxQ1eQY;`=uhlmVcgxozE_(vzz+b5hAc6BLVPTXW;06 z`PtOi@-K9a=*x4;N@hh_2K?n03!5aREzf2ZeIxOawvw1E786UGMuB9M?D8!8;3OJY(S*6VEj3V#cA)BvWSYNR@yXK*l@0&u;~tK4a@b(&*WLhE&at9+V=c|90apFL+!wwsF6 zeA+jS?%rI69k=;yUx|m=#5OkSi5Q`EziVH@-gLPwl!Wzqco9F$7%=RXj~JaUkI-u? z#S$(#-oP0+tt7q&%-;KZb2j{idD^@9v)hxmr{-qvd@L{hd~)hT`Od=ht=U^slS{W2 z<`=1$$pi2J)SE?BF*GVd*3=9w9wzJ+343oULdH#JR;e$q-KT<@AqL>bu~SJqv+%<% zMJ;8}FiX-I6~ZI~Mq!teH?%FvXH*CiJN?S3H6;&ljr;8|Aiee`27G7D&}jhRPi&}C z(UDO>hr*yyAMB&Ev+Q>oIRiZDa>+$t^d~?7$D!_W=&ThwTSc7ET9G2V;=e*&R;b79 zy}os07!xC&OYzx`uzt7_sSg?td0x2GnI=8>*AOh{b2uXD>`UK2mir88TniA@4?-v z%B3HDea(F5`tD6DeE#rCIXq;BhpK+IRmgn`>4BHLA?%O0AC&I z-k{j#N?a4r-xLOQ*pq3a4l;mZQ$QRx)h_U{*1S)81@gQRaqSQ~tb@NHgC}q${ww|n zJbzsGp51g7?cXEcJUIvEtl+yy3N!(>T?QP_imcOTpcwzi`v}^yq6-zveU40t6T8@oav5|6g)QXPo z`kzaE&!oYp(%|9Z*F&Z>SeC{tY0PwcRe<&OCf@;}AOCM4boc)OLLTVWGcA0#dh4=_6IuqjiyvRBKqbI5USKF-?_N+!UPbOUiNNKUM=GEEryh$&cx+(8u_ zvT*k^-2W8!m+^TEpEuoZdl|=0fnk?U!ZH|PSH`&LNLlK!YY*x3>T9cPePh*W8kFVq zCj1A`WSOu$0QG6Bn8~kF&Y;1@rOPRbZ4JS&b90O|N#KtL73|xZU1V)o(H2`UtY=p9 zN>(QeUT+6{6CRO~zHb3m&;j^irmyy@*HC~CU>1jS6ZS6l`p71U|Ey@Gm7Z?B+p zrngtnfa&cgKKy`HXYO1D_nY2+66)B!_Qm+#_>Oeae&*rC? dict[str, t.Any]: + """Registered with :meth:`~flask.Flask.shell_context_processor` if + ``add_models_to_shell`` is enabled. Adds the ``db`` instance and all model classes + to ``flask shell``. + """ + db = current_app.extensions["sqlalchemy"] + out = {m.class_.__name__: m.class_ for m in db.Model._sa_registry.mappers} + out["db"] = db + return out diff --git a/.venv/Lib/site-packages/flask_sqlalchemy/extension.py b/.venv/Lib/site-packages/flask_sqlalchemy/extension.py new file mode 100644 index 000000000..a64ced0a5 --- /dev/null +++ b/.venv/Lib/site-packages/flask_sqlalchemy/extension.py @@ -0,0 +1,1005 @@ +from __future__ import annotations + +import os +import typing as t +from weakref import WeakKeyDictionary + +import sqlalchemy as sa +import sqlalchemy.event +import sqlalchemy.exc +import sqlalchemy.orm +from flask import abort +from flask import current_app +from flask import Flask +from flask import has_app_context + +from .model import _QueryProperty +from .model import DefaultMeta +from .model import Model +from .pagination import Pagination +from .pagination import SelectPagination +from .query import Query +from .session import _app_ctx_id +from .session import Session +from .table import _Table + + +class SQLAlchemy: + """Integrates SQLAlchemy with Flask. This handles setting up one or more engines, + associating tables and models with specific engines, and cleaning up connections and + sessions after each request. + + Only the engine configuration is specific to each application, other things like + the model, table, metadata, and session are shared for all applications using that + extension instance. Call :meth:`init_app` to configure the extension on an + application. + + After creating the extension, create model classes by subclassing :attr:`Model`, and + table classes with :attr:`Table`. These can be accessed before :meth:`init_app` is + called, making it possible to define the models separately from the application. + + Accessing :attr:`session` and :attr:`engine` requires an active Flask application + context. This includes methods like :meth:`create_all` which use the engine. + + This class also provides access to names in SQLAlchemy's ``sqlalchemy`` and + ``sqlalchemy.orm`` modules. For example, you can use ``db.Column`` and + ``db.relationship`` instead of importing ``sqlalchemy.Column`` and + ``sqlalchemy.orm.relationship``. This can be convenient when defining models. + + :param app: Call :meth:`init_app` on this Flask application now. + :param metadata: Use this as the default :class:`sqlalchemy.schema.MetaData`. Useful + for setting a naming convention. + :param session_options: Arguments used by :attr:`session` to create each session + instance. A ``scopefunc`` key will be passed to the scoped session, not the + session instance. See :class:`sqlalchemy.orm.sessionmaker` for a list of + arguments. + :param query_class: Use this as the default query class for models and dynamic + relationships. The query interface is considered legacy in SQLAlchemy. + :param model_class: Use this as the model base class when creating the declarative + model class :attr:`Model`. Can also be a fully created declarative model class + for further customization. + :param engine_options: Default arguments used when creating every engine. These are + lower precedence than application config. See :func:`sqlalchemy.create_engine` + for a list of arguments. + :param add_models_to_shell: Add the ``db`` instance and all model classes to + ``flask shell``. + + .. versionchanged:: 3.0 + An active Flask application context is always required to access ``session`` and + ``engine``. + + .. versionchanged:: 3.0 + Separate ``metadata`` are used for each bind key. + + .. versionchanged:: 3.0 + The ``engine_options`` parameter is applied as defaults before per-engine + configuration. + + .. versionchanged:: 3.0 + The session class can be customized in ``session_options``. + + .. versionchanged:: 3.0 + Added the ``add_models_to_shell`` parameter. + + .. versionchanged:: 3.0 + Engines are created when calling ``init_app`` rather than the first time they + are accessed. + + .. versionchanged:: 3.0 + All parameters except ``app`` are keyword-only. + + .. versionchanged:: 3.0 + The extension instance is stored directly as ``app.extensions["sqlalchemy"]``. + + .. versionchanged:: 3.0 + Setup methods are renamed with a leading underscore. They are considered + internal interfaces which may change at any time. + + .. versionchanged:: 3.0 + Removed the ``use_native_unicode`` parameter and config. + + .. versionchanged:: 3.0 + The ``COMMIT_ON_TEARDOWN`` configuration is deprecated and will + be removed in Flask-SQLAlchemy 3.1. Call ``db.session.commit()`` + directly instead. + + .. versionchanged:: 2.4 + Added the ``engine_options`` parameter. + + .. versionchanged:: 2.1 + Added the ``metadata``, ``query_class``, and ``model_class`` parameters. + + .. versionchanged:: 2.1 + Use the same query class across ``session``, ``Model.query`` and + ``Query``. + + .. versionchanged:: 0.16 + ``scopefunc`` is accepted in ``session_options``. + + .. versionchanged:: 0.10 + Added the ``session_options`` parameter. + """ + + def __init__( + self, + app: Flask | None = None, + *, + metadata: sa.MetaData | None = None, + session_options: dict[str, t.Any] | None = None, + query_class: type[Query] = Query, + model_class: type[Model] | sa.orm.DeclarativeMeta = Model, + engine_options: dict[str, t.Any] | None = None, + add_models_to_shell: bool = True, + ): + if session_options is None: + session_options = {} + + self.Query = query_class + """The default query class used by ``Model.query`` and ``lazy="dynamic"`` + relationships. + + .. warning:: + The query interface is considered legacy in SQLAlchemy. + + Customize this by passing the ``query_class`` parameter to the extension. + """ + + self.session = self._make_scoped_session(session_options) + """A :class:`sqlalchemy.orm.scoping.scoped_session` that creates instances of + :class:`.Session` scoped to the current Flask application context. The session + will be removed, returning the engine connection to the pool, when the + application context exits. + + Customize this by passing ``session_options`` to the extension. + + This requires that a Flask application context is active. + + .. versionchanged:: 3.0 + The session is scoped to the current app context. + """ + + self.metadatas: dict[str | None, sa.MetaData] = {} + """Map of bind keys to :class:`sqlalchemy.schema.MetaData` instances. The + ``None`` key refers to the default metadata, and is available as + :attr:`metadata`. + + Customize the default metadata by passing the ``metadata`` parameter to the + extension. This can be used to set a naming convention. When metadata for + another bind key is created, it copies the default's naming convention. + + .. versionadded:: 3.0 + """ + + if metadata is not None: + metadata.info["bind_key"] = None + self.metadatas[None] = metadata + + self.Table = self._make_table_class() + """A :class:`sqlalchemy.schema.Table` class that chooses a metadata + automatically. + + Unlike the base ``Table``, the ``metadata`` argument is not required. If it is + not given, it is selected based on the ``bind_key`` argument. + + :param bind_key: Used to select a different metadata. + :param args: Arguments passed to the base class. These are typically the table's + name, columns, and constraints. + :param kwargs: Arguments passed to the base class. + + .. versionchanged:: 3.0 + This is a subclass of SQLAlchemy's ``Table`` rather than a function. + """ + + self.Model = self._make_declarative_base(model_class) + """A SQLAlchemy declarative model class. Subclass this to define database + models. + + If a model does not set ``__tablename__``, it will be generated by converting + the class name from ``CamelCase`` to ``snake_case``. It will not be generated + if the model looks like it uses single-table inheritance. + + If a model or parent class sets ``__bind_key__``, it will use that metadata and + database engine. Otherwise, it will use the default :attr:`metadata` and + :attr:`engine`. This is ignored if the model sets ``metadata`` or ``__table__``. + + Customize this by subclassing :class:`.Model` and passing the ``model_class`` + parameter to the extension. A fully created declarative model class can be + passed as well, to use a custom metaclass. + """ + + if engine_options is None: + engine_options = {} + + self._engine_options = engine_options + self._app_engines: WeakKeyDictionary[Flask, dict[str | None, sa.engine.Engine]] + self._app_engines = WeakKeyDictionary() + self._add_models_to_shell = add_models_to_shell + + if app is not None: + self.init_app(app) + + def __repr__(self) -> str: + if not has_app_context(): + return f"<{type(self).__name__}>" + + message = f"{type(self).__name__} {self.engine.url}" + + if len(self.engines) > 1: + message = f"{message} +{len(self.engines) - 1}" + + return f"<{message}>" + + def init_app(self, app: Flask) -> None: + """Initialize a Flask application for use with this extension instance. This + must be called before accessing the database engine or session with the app. + + This sets default configuration values, then configures the extension on the + application and creates the engines for each bind key. Therefore, this must be + called after the application has been configured. Changes to application config + after this call will not be reflected. + + The following keys from ``app.config`` are used: + + - :data:`.SQLALCHEMY_DATABASE_URI` + - :data:`.SQLALCHEMY_ENGINE_OPTIONS` + - :data:`.SQLALCHEMY_ECHO` + - :data:`.SQLALCHEMY_BINDS` + - :data:`.SQLALCHEMY_RECORD_QUERIES` + - :data:`.SQLALCHEMY_TRACK_MODIFICATIONS` + + :param app: The Flask application to initialize. + """ + if "sqlalchemy" in app.extensions: + raise RuntimeError( + "A 'SQLAlchemy' instance has already been registered on this Flask app." + " Import and use that instance instead." + ) + + app.extensions["sqlalchemy"] = self + + if self._add_models_to_shell: + from .cli import add_models_to_shell + + app.shell_context_processor(add_models_to_shell) + + if app.config.get("SQLALCHEMY_COMMIT_ON_TEARDOWN", False): + import warnings + + warnings.warn( + "'SQLALCHEMY_COMMIT_ON_TEARDOWN' is deprecated and will be removed in" + " Flask-SQAlchemy 3.1. Call 'db.session.commit()'` directly instead.", + DeprecationWarning, + ) + app.teardown_appcontext(self._teardown_commit) + else: + app.teardown_appcontext(self._teardown_session) + + basic_uri: str | sa.engine.URL | None = app.config.setdefault( + "SQLALCHEMY_DATABASE_URI", None + ) + basic_engine_options = self._engine_options.copy() + basic_engine_options.update( + app.config.setdefault("SQLALCHEMY_ENGINE_OPTIONS", {}) + ) + echo: bool = app.config.setdefault("SQLALCHEMY_ECHO", False) + config_binds: dict[ + str | None, str | sa.engine.URL | dict[str, t.Any] + ] = app.config.setdefault("SQLALCHEMY_BINDS", {}) + engine_options: dict[str | None, dict[str, t.Any]] = {} + + # Build the engine config for each bind key. + for key, value in config_binds.items(): + engine_options[key] = self._engine_options.copy() + + if isinstance(value, (str, sa.engine.URL)): + engine_options[key]["url"] = value + else: + engine_options[key].update(value) + + # Build the engine config for the default bind key. + if basic_uri is not None: + basic_engine_options["url"] = basic_uri + + if "url" in basic_engine_options: + engine_options.setdefault(None, {}).update(basic_engine_options) + + if not engine_options: + raise RuntimeError( + "Either 'SQLALCHEMY_DATABASE_URI' or 'SQLALCHEMY_BINDS' must be set." + ) + + engines = self._app_engines.setdefault(app, {}) + + # Dispose existing engines in case init_app is called again. + if engines: + for engine in engines.values(): + engine.dispose() + + engines.clear() + + # Create the metadata and engine for each bind key. + for key, options in engine_options.items(): + self._make_metadata(key) + options.setdefault("echo", echo) + options.setdefault("echo_pool", echo) + self._apply_driver_defaults(options, app) + engines[key] = self._make_engine(key, options, app) + + if app.config.setdefault("SQLALCHEMY_RECORD_QUERIES", False): + from . import record_queries + + for engine in engines.values(): + record_queries._listen(engine) + + if app.config.setdefault("SQLALCHEMY_TRACK_MODIFICATIONS", False): + from . import track_modifications + + track_modifications._listen(self.session) + + def _make_scoped_session( + self, options: dict[str, t.Any] + ) -> sa.orm.scoped_session[Session]: + """Create a :class:`sqlalchemy.orm.scoping.scoped_session` around the factory + from :meth:`_make_session_factory`. The result is available as :attr:`session`. + + The scope function can be customized using the ``scopefunc`` key in the + ``session_options`` parameter to the extension. By default it uses the current + thread or greenlet id. + + This method is used for internal setup. Its signature may change at any time. + + :meta private: + + :param options: The ``session_options`` parameter from ``__init__``. Keyword + arguments passed to the session factory. A ``scopefunc`` key is popped. + + .. versionchanged:: 3.0 + The session is scoped to the current app context. + + .. versionchanged:: 3.0 + Renamed from ``create_scoped_session``, this method is internal. + """ + scope = options.pop("scopefunc", _app_ctx_id) + factory = self._make_session_factory(options) + return sa.orm.scoped_session(factory, scope) + + def _make_session_factory( + self, options: dict[str, t.Any] + ) -> sa.orm.sessionmaker[Session]: + """Create the SQLAlchemy :class:`sqlalchemy.orm.sessionmaker` used by + :meth:`_make_scoped_session`. + + To customize, pass the ``session_options`` parameter to :class:`SQLAlchemy`. To + customize the session class, subclass :class:`.Session` and pass it as the + ``class_`` key. + + This method is used for internal setup. Its signature may change at any time. + + :meta private: + + :param options: The ``session_options`` parameter from ``__init__``. Keyword + arguments passed to the session factory. + + .. versionchanged:: 3.0 + The session class can be customized. + + .. versionchanged:: 3.0 + Renamed from ``create_session``, this method is internal. + """ + options.setdefault("class_", Session) + options.setdefault("query_cls", self.Query) + return sa.orm.sessionmaker(db=self, **options) + + def _teardown_commit(self, exc: BaseException | None) -> None: + """Commit the session at the end of the request if there was not an unhandled + exception during the request. + + :meta private: + + .. deprecated:: 3.0 + Will be removed in 3.1. Use ``db.session.commit()`` directly instead. + """ + if exc is None: + self.session.commit() + + self.session.remove() + + def _teardown_session(self, exc: BaseException | None) -> None: + """Remove the current session at the end of the request. + + :meta private: + + .. versionadded:: 3.0 + """ + self.session.remove() + + def _make_metadata(self, bind_key: str | None) -> sa.MetaData: + """Get or create a :class:`sqlalchemy.schema.MetaData` for the given bind key. + + This method is used for internal setup. Its signature may change at any time. + + :meta private: + + :param bind_key: The name of the metadata being created. + + .. versionadded:: 3.0 + """ + if bind_key in self.metadatas: + return self.metadatas[bind_key] + + if bind_key is not None: + # Copy the naming convention from the default metadata. + naming_convention = self._make_metadata(None).naming_convention + else: + naming_convention = None + + # Set the bind key in info to be used by session.get_bind. + metadata = sa.MetaData( + naming_convention=naming_convention, info={"bind_key": bind_key} + ) + self.metadatas[bind_key] = metadata + return metadata + + def _make_table_class(self) -> type[_Table]: + """Create a SQLAlchemy :class:`sqlalchemy.schema.Table` class that chooses a + metadata automatically based on the ``bind_key``. The result is available as + :attr:`Table`. + + This method is used for internal setup. Its signature may change at any time. + + :meta private: + + .. versionadded:: 3.0 + """ + + class Table(_Table): + def __new__( + cls, *args: t.Any, bind_key: str | None = None, **kwargs: t.Any + ) -> Table: + # If a metadata arg is passed, go directly to the base Table. Also do + # this for no args so the correct error is shown. + if not args or (len(args) >= 2 and isinstance(args[1], sa.MetaData)): + return super().__new__(cls, *args, **kwargs) + + if ( + bind_key is None + and "info" in kwargs + and "bind_key" in kwargs["info"] + ): + import warnings + + warnings.warn( + "'table.info['bind_key'] is deprecated and will not be used in" + " Flask-SQLAlchemy 3.1. Pass the 'bind_key' parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + bind_key = kwargs["info"].get("bind_key") + + metadata = self._make_metadata(bind_key) + return super().__new__(cls, *[args[0], metadata, *args[1:]], **kwargs) + + return Table + + def _make_declarative_base( + self, model: type[Model] | sa.orm.DeclarativeMeta + ) -> type[t.Any]: + """Create a SQLAlchemy declarative model class. The result is available as + :attr:`Model`. + + To customize, subclass :class:`.Model` and pass it as ``model_class`` to + :class:`SQLAlchemy`. To customize at the metaclass level, pass an already + created declarative model class as ``model_class``. + + This method is used for internal setup. Its signature may change at any time. + + :meta private: + + :param model: A model base class, or an already created declarative model class. + + .. versionchanged:: 3.0 + Renamed with a leading underscore, this method is internal. + + .. versionchanged:: 2.3 + ``model`` can be an already created declarative model class. + """ + if not isinstance(model, sa.orm.DeclarativeMeta): + metadata = self._make_metadata(None) + model = sa.orm.declarative_base( + metadata=metadata, cls=model, name="Model", metaclass=DefaultMeta + ) + + if None not in self.metadatas: + # Use the model's metadata as the default metadata. + model.metadata.info["bind_key"] = None # type: ignore[union-attr] + self.metadatas[None] = model.metadata # type: ignore[union-attr] + else: + # Use the passed in default metadata as the model's metadata. + model.metadata = self.metadatas[None] # type: ignore[union-attr] + + model.query_class = self.Query + model.query = _QueryProperty() + model.__fsa__ = self + return model + + def _apply_driver_defaults(self, options: dict[str, t.Any], app: Flask) -> None: + """Apply driver-specific configuration to an engine. + + SQLite in-memory databases use ``StaticPool`` and disable ``check_same_thread``. + File paths are relative to the app's :attr:`~flask.Flask.instance_path`, + which is created if it doesn't exist. + + MySQL sets ``charset="utf8mb4"``, and ``pool_timeout`` defaults to 2 hours. + + This method is used for internal setup. Its signature may change at any time. + + :meta private: + + :param options: Arguments passed to the engine. + :param app: The application that the engine configuration belongs to. + + .. versionchanged:: 3.0 + SQLite paths are relative to ``app.instance_path``. It does not use + ``NullPool`` if ``pool_size`` is 0. Driver-level URIs are supported. + + .. versionchanged:: 3.0 + MySQL sets ``charset="utf8mb4". It does not set ``pool_size`` to 10. It + does not set ``pool_recycle`` if not using a queue pool. + + .. versionchanged:: 3.0 + Renamed from ``apply_driver_hacks``, this method is internal. It does not + return anything. + + .. versionchanged:: 2.5 + Returns ``(sa_url, options)``. + """ + url = sa.engine.make_url(options["url"]) + + if url.drivername in {"sqlite", "sqlite+pysqlite"}: + if url.database is None or url.database in {"", ":memory:"}: + options["poolclass"] = sa.pool.StaticPool + + if "connect_args" not in options: + options["connect_args"] = {} + + options["connect_args"]["check_same_thread"] = False + else: + # the url might look like sqlite:///file:path?uri=true + is_uri = url.query.get("uri", False) + + if is_uri: + db_str = url.database[5:] + else: + db_str = url.database + + if not os.path.isabs(db_str): + os.makedirs(app.instance_path, exist_ok=True) + db_str = os.path.join(app.instance_path, db_str) + + if is_uri: + db_str = f"file:{db_str}" + + options["url"] = url.set(database=db_str) + elif url.drivername.startswith("mysql"): + # set queue defaults only when using queue pool + if ( + "pool_class" not in options + or options["pool_class"] is sa.pool.QueuePool + ): + options.setdefault("pool_recycle", 7200) + + if "charset" not in url.query: + options["url"] = url.update_query_dict({"charset": "utf8mb4"}) + + def _make_engine( + self, bind_key: str | None, options: dict[str, t.Any], app: Flask + ) -> sa.engine.Engine: + """Create the :class:`sqlalchemy.engine.Engine` for the given bind key and app. + + To customize, use :data:`.SQLALCHEMY_ENGINE_OPTIONS` or + :data:`.SQLALCHEMY_BINDS` config. Pass ``engine_options`` to :class:`SQLAlchemy` + to set defaults for all engines. + + This method is used for internal setup. Its signature may change at any time. + + :meta private: + + :param bind_key: The name of the engine being created. + :param options: Arguments passed to the engine. + :param app: The application that the engine configuration belongs to. + + .. versionchanged:: 3.0 + Renamed from ``create_engine``, this method is internal. + """ + return sa.engine_from_config(options, prefix="") + + @property + def metadata(self) -> sa.MetaData: + """The default metadata used by :attr:`Model` and :attr:`Table` if no bind key + is set. + """ + return self.metadatas[None] + + @property + def engines(self) -> t.Mapping[str | None, sa.engine.Engine]: + """Map of bind keys to :class:`sqlalchemy.engine.Engine` instances for current + application. The ``None`` key refers to the default engine, and is available as + :attr:`engine`. + + To customize, set the :data:`.SQLALCHEMY_BINDS` config, and set defaults by + passing the ``engine_options`` parameter to the extension. + + This requires that a Flask application context is active. + + .. versionadded:: 3.0 + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + + if app not in self._app_engines: + raise RuntimeError( + "The current Flask app is not registered with this 'SQLAlchemy'" + " instance. Did you forget to call 'init_app', or did you create" + " multiple 'SQLAlchemy' instances?" + ) + + return self._app_engines[app] + + @property + def engine(self) -> sa.engine.Engine: + """The default :class:`~sqlalchemy.engine.Engine` for the current application, + used by :attr:`session` if the :attr:`Model` or :attr:`Table` being queried does + not set a bind key. + + To customize, set the :data:`.SQLALCHEMY_ENGINE_OPTIONS` config, and set + defaults by passing the ``engine_options`` parameter to the extension. + + This requires that a Flask application context is active. + """ + return self.engines[None] + + def get_engine(self, bind_key: str | None = None) -> sa.engine.Engine: + """Get the engine for the given bind key for the current application. + + This requires that a Flask application context is active. + + :param bind_key: The name of the engine. + + .. deprecated:: 3.0 + Will be removed in Flask-SQLAlchemy 3.1. Use ``engines[key]`` instead. + + .. versionchanged:: 3.0 + Renamed the ``bind`` parameter to ``bind_key``. Removed the ``app`` + parameter. + """ + import warnings + + warnings.warn( + "'get_engine' is deprecated and will be removed in Flask-SQLAlchemy 3.1." + " Use 'engine' or 'engines[key]' instead.", + DeprecationWarning, + stacklevel=2, + ) + return self.engines[bind_key] + + def get_tables_for_bind(self, bind_key: str | None = None) -> list[sa.Table]: + """Get all tables in the metadata for the given bind key. + + :param bind_key: The bind key to get. + + .. deprecated:: 3.0 + Will be removed in Flask-SQLAlchemy 3.1. Use ``metadata.tables`` instead. + + .. versionchanged:: 3.0 + Renamed the ``bind`` parameter to ``bind_key``. + """ + import warnings + + warnings.warn( + "'get_tables_for_bind' is deprecated and will be removed in" + " Flask-SQLAlchemy 3.1. Use 'metadata.tables' instead.", + DeprecationWarning, + stacklevel=2, + ) + return list(self.metadatas[bind_key].tables.values()) + + def get_binds(self) -> dict[sa.Table, sa.engine.Engine]: + """Map all tables to their engine based on their bind key, which can be used to + create a session with ``Session(binds=db.get_binds(app))``. + + This requires that a Flask application context is active. + + .. deprecated:: 3.0 + Will be removed in Flask-SQLAlchemy 3.1. ``db.session`` supports multiple + binds directly. + + .. versionchanged:: 3.0 + Removed the ``app`` parameter. + """ + import warnings + + warnings.warn( + "'get_binds' is deprecated and will be removed in Flask-SQLAlchemy 3.1." + " 'db.session' supports multiple binds directly.", + DeprecationWarning, + stacklevel=2, + ) + return { + table: engine + for bind_key, engine in self.engines.items() + for table in self.metadatas[bind_key].tables.values() + } + + def get_or_404( + self, entity: type[t.Any], ident: t.Any, *, description: str | None = None + ) -> t.Any: + """Like :meth:`session.get() ` but aborts with a + ``404 Not Found`` error instead of returning ``None``. + + :param entity: The model class to query. + :param ident: The primary key to query. + :param description: A custom message to show on the error page. + + .. versionadded:: 3.0 + """ + value = self.session.get(entity, ident) + + if value is None: + abort(404, description=description) + + return value + + def first_or_404( + self, statement: sa.sql.Select[t.Any], *, description: str | None = None + ) -> t.Any: + """Like :meth:`Result.scalar() `, but aborts + with a ``404 Not Found`` error instead of returning ``None``. + + :param statement: The ``select`` statement to execute. + :param description: A custom message to show on the error page. + + .. versionadded:: 3.0 + """ + value = self.session.execute(statement).scalar() + + if value is None: + abort(404, description=description) + + return value + + def one_or_404( + self, statement: sa.sql.Select[t.Any], *, description: str | None = None + ) -> t.Any: + """Like :meth:`Result.scalar_one() `, + but aborts with a ``404 Not Found`` error instead of raising ``NoResultFound`` + or ``MultipleResultsFound``. + + :param statement: The ``select`` statement to execute. + :param description: A custom message to show on the error page. + + .. versionadded:: 3.0 + """ + try: + return self.session.execute(statement).scalar_one() + except (sa.exc.NoResultFound, sa.exc.MultipleResultsFound): + abort(404, description=description) + + def paginate( + self, + select: sa.sql.Select[t.Any], + *, + page: int | None = None, + per_page: int | None = None, + max_per_page: int | None = None, + error_out: bool = True, + count: bool = True, + ) -> Pagination: + """Apply an offset and limit to a select statment based on the current page and + number of items per page, returning a :class:`.Pagination` object. + + The statement should select a model class, like ``select(User)``. This applies + ``unique()`` and ``scalars()`` modifiers to the result, so compound selects will + not return the expected results. + + :param select: The ``select`` statement to paginate. + :param page: The current page, used to calculate the offset. Defaults to the + ``page`` query arg during a request, or 1 otherwise. + :param per_page: The maximum number of items on a page, used to calculate the + offset and limit. Defaults to the ``per_page`` query arg during a request, + or 20 otherwise. + :param max_per_page: The maximum allowed value for ``per_page``, to limit a + user-provided value. Use ``None`` for no limit. Defaults to 100. + :param error_out: Abort with a ``404 Not Found`` error if no items are returned + and ``page`` is not 1, or if ``page`` or ``per_page`` is less than 1, or if + either are not ints. + :param count: Calculate the total number of values by issuing an extra count + query. For very complex queries this may be inaccurate or slow, so it can be + disabled and set manually if necessary. + + .. versionchanged:: 3.0 + The ``count`` query is more efficient. + + .. versionadded:: 3.0 + """ + return SelectPagination( + select=select, + session=self.session(), + page=page, + per_page=per_page, + max_per_page=max_per_page, + error_out=error_out, + count=count, + ) + + def _call_for_binds( + self, bind_key: str | None | list[str | None], op_name: str + ) -> None: + """Call a method on each metadata. + + :meta private: + + :param bind_key: A bind key or list of keys. Defaults to all binds. + :param op_name: The name of the method to call. + + .. versionchanged:: 3.0 + Renamed from ``_execute_for_all_tables``. + """ + if bind_key == "__all__": + keys: list[str | None] = list(self.metadatas) + elif bind_key is None or isinstance(bind_key, str): + keys = [bind_key] + else: + keys = bind_key + + for key in keys: + try: + engine = self.engines[key] + except KeyError: + message = f"Bind key '{key}' is not in 'SQLALCHEMY_BINDS' config." + + if key is None: + message = f"'SQLALCHEMY_DATABASE_URI' config is not set. {message}" + + raise sa.exc.UnboundExecutionError(message) from None + + metadata = self.metadatas[key] + getattr(metadata, op_name)(bind=engine) + + def create_all(self, bind_key: str | None | list[str | None] = "__all__") -> None: + """Create tables that do not exist in the database by calling + ``metadata.create_all()`` for all or some bind keys. This does not + update existing tables, use a migration library for that. + + This requires that a Flask application context is active. + + :param bind_key: A bind key or list of keys to create the tables for. Defaults + to all binds. + + .. versionchanged:: 3.0 + Renamed the ``bind`` parameter to ``bind_key``. Removed the ``app`` + parameter. + + .. versionchanged:: 0.12 + Added the ``bind`` and ``app`` parameters. + """ + self._call_for_binds(bind_key, "create_all") + + def drop_all(self, bind_key: str | None | list[str | None] = "__all__") -> None: + """Drop tables by calling ``metadata.drop_all()`` for all or some bind keys. + + This requires that a Flask application context is active. + + :param bind_key: A bind key or list of keys to drop the tables from. Defaults to + all binds. + + .. versionchanged:: 3.0 + Renamed the ``bind`` parameter to ``bind_key``. Removed the ``app`` + parameter. + + .. versionchanged:: 0.12 + Added the ``bind`` and ``app`` parameters. + """ + self._call_for_binds(bind_key, "drop_all") + + def reflect(self, bind_key: str | None | list[str | None] = "__all__") -> None: + """Load table definitions from the database by calling ``metadata.reflect()`` + for all or some bind keys. + + This requires that a Flask application context is active. + + :param bind_key: A bind key or list of keys to reflect the tables from. Defaults + to all binds. + + .. versionchanged:: 3.0 + Renamed the ``bind`` parameter to ``bind_key``. Removed the ``app`` + parameter. + + .. versionchanged:: 0.12 + Added the ``bind`` and ``app`` parameters. + """ + self._call_for_binds(bind_key, "reflect") + + def _set_rel_query(self, kwargs: dict[str, t.Any]) -> None: + """Apply the extension's :attr:`Query` class as the default for relationships + and backrefs. + + :meta private: + """ + kwargs.setdefault("query_class", self.Query) + + if "backref" in kwargs: + backref = kwargs["backref"] + + if isinstance(backref, str): + backref = (backref, {}) + + backref[1].setdefault("query_class", self.Query) + + def relationship( + self, *args: t.Any, **kwargs: t.Any + ) -> sa.orm.RelationshipProperty[t.Any]: + """A :func:`sqlalchemy.orm.relationship` that applies this extension's + :attr:`Query` class for dynamic relationships and backrefs. + + .. versionchanged:: 3.0 + The :attr:`Query` class is set on ``backref``. + """ + self._set_rel_query(kwargs) + return sa.orm.relationship(*args, **kwargs) + + def dynamic_loader( + self, argument: t.Any, **kwargs: t.Any + ) -> sa.orm.RelationshipProperty[t.Any]: + """A :func:`sqlalchemy.orm.dynamic_loader` that applies this extension's + :attr:`Query` class for relationships and backrefs. + + .. versionchanged:: 3.0 + The :attr:`Query` class is set on ``backref``. + """ + self._set_rel_query(kwargs) + return sa.orm.dynamic_loader(argument, **kwargs) + + def _relation( + self, *args: t.Any, **kwargs: t.Any + ) -> sa.orm.RelationshipProperty[t.Any]: + """A :func:`sqlalchemy.orm.relationship` that applies this extension's + :attr:`Query` class for dynamic relationships and backrefs. + + SQLAlchemy 2.0 removes this name, use ``relationship`` instead. + + :meta private: + + .. versionchanged:: 3.0 + The :attr:`Query` class is set on ``backref``. + """ + # Deprecated, removed in SQLAlchemy 2.0. Accessed through ``__getattr__``. + self._set_rel_query(kwargs) + f = sa.orm.relation # type: ignore[attr-defined] + return f(*args, **kwargs) # type: ignore[no-any-return] + + def __getattr__(self, name: str) -> t.Any: + if name == "db": + import warnings + + warnings.warn( + "The 'db' attribute is deprecated and will be removed in" + " Flask-SQLAlchemy 3.1. The extension is registered directly as" + " 'app.extensions[\"sqlalchemy\"]'.", + DeprecationWarning, + stacklevel=2, + ) + return self + + if name == "relation": + return self._relation + + if name == "event": + return sa.event + + if name.startswith("_"): + raise AttributeError(name) + + for mod in (sa, sa.orm): + if hasattr(mod, name): + return getattr(mod, name) + + raise AttributeError(name) diff --git a/.venv/Lib/site-packages/flask_sqlalchemy/model.py b/.venv/Lib/site-packages/flask_sqlalchemy/model.py new file mode 100644 index 000000000..e49bda058 --- /dev/null +++ b/.venv/Lib/site-packages/flask_sqlalchemy/model.py @@ -0,0 +1,214 @@ +from __future__ import annotations + +import re +import typing as t + +import sqlalchemy as sa +import sqlalchemy.orm + +from .query import Query + +if t.TYPE_CHECKING: + from .extension import SQLAlchemy + + +class _QueryProperty: + """A class property that creates a query object for a model. + + :meta private: + """ + + @t.overload + def __get__(self, obj: None, cls: type[Model]) -> Query: + ... + + @t.overload + def __get__(self, obj: Model, cls: type[Model]) -> Query: + ... + + def __get__(self, obj: Model | None, cls: type[Model]) -> Query: + return cls.query_class( + cls, session=cls.__fsa__.session() # type: ignore[arg-type] + ) + + +class Model: + """The base class of the :attr:`.SQLAlchemy.Model` declarative model class. + + To define models, subclass :attr:`db.Model <.SQLAlchemy.Model>`, not this. To + customize ``db.Model``, subclass this and pass it as ``model_class`` to + :class:`.SQLAlchemy`. To customize ``db.Model`` at the metaclass level, pass an + already created declarative model class as ``model_class``. + """ + + __fsa__: t.ClassVar[SQLAlchemy] + """Internal reference to the extension object. + + :meta private: + """ + + query_class: t.ClassVar[type[Query]] = Query + """Query class used by :attr:`query`. Defaults to :attr:`.SQLAlchemy.Query`, which + defaults to :class:`.Query`. + """ + + query: t.ClassVar[Query] = _QueryProperty() # type: ignore[assignment] + """A SQLAlchemy query for a model. Equivalent to ``db.session.query(Model)``. Can be + customized per-model by overriding :attr:`query_class`. + + .. warning:: + The query interface is considered legacy in SQLAlchemy. Prefer using + ``session.execute(select())`` instead. + """ + + def __repr__(self) -> str: + state = sa.inspect(self) + assert state is not None + + if state.transient: + pk = f"(transient {id(self)})" + elif state.pending: + pk = f"(pending {id(self)})" + else: + pk = ", ".join(map(str, state.identity)) + + return f"<{type(self).__name__} {pk}>" + + +class BindMetaMixin(type): + """Metaclass mixin that sets a model's ``metadata`` based on its ``__bind_key__``. + + If the model sets ``metadata`` or ``__table__`` directly, ``__bind_key__`` is + ignored. If the ``metadata`` is the same as the parent model, it will not be set + directly on the child model. + """ + + __fsa__: SQLAlchemy + metadata: sa.MetaData + + def __init__( + cls, name: str, bases: tuple[type, ...], d: dict[str, t.Any], **kwargs: t.Any + ) -> None: + if not ("metadata" in cls.__dict__ or "__table__" in cls.__dict__): + bind_key = getattr(cls, "__bind_key__", None) + parent_metadata = getattr(cls, "metadata", None) + metadata = cls.__fsa__._make_metadata(bind_key) + + if metadata is not parent_metadata: + cls.metadata = metadata + + super().__init__(name, bases, d, **kwargs) + + +class NameMetaMixin(type): + """Metaclass mixin that sets a model's ``__tablename__`` by converting the + ``CamelCase`` class name to ``snake_case``. A name is set for non-abstract models + that do not otherwise define ``__tablename__``. If a model does not define a primary + key, it will not generate a name or ``__table__``, for single-table inheritance. + """ + + metadata: sa.MetaData + __tablename__: str + __table__: sa.Table + + def __init__( + cls, name: str, bases: tuple[type, ...], d: dict[str, t.Any], **kwargs: t.Any + ) -> None: + if should_set_tablename(cls): + cls.__tablename__ = camel_to_snake_case(cls.__name__) + + super().__init__(name, bases, d, **kwargs) + + # __table_cls__ has run. If no table was created, use the parent table. + if ( + "__tablename__" not in cls.__dict__ + and "__table__" in cls.__dict__ + and cls.__dict__["__table__"] is None + ): + del cls.__table__ + + def __table_cls__(cls, *args: t.Any, **kwargs: t.Any) -> sa.Table | None: + """This is called by SQLAlchemy during mapper setup. It determines the final + table object that the model will use. + + If no primary key is found, that indicates single-table inheritance, so no table + will be created and ``__tablename__`` will be unset. + """ + schema = kwargs.get("schema") + + if schema is None: + key = args[0] + else: + key = f"{schema}.{args[0]}" + + # Check if a table with this name already exists. Allows reflected tables to be + # applied to models by name. + if key in cls.metadata.tables: + return sa.Table(*args, **kwargs) + + # If a primary key is found, create a table for joined-table inheritance. + for arg in args: + if (isinstance(arg, sa.Column) and arg.primary_key) or isinstance( + arg, sa.PrimaryKeyConstraint + ): + return sa.Table(*args, **kwargs) + + # If no base classes define a table, return one that's missing a primary key + # so SQLAlchemy shows the correct error. + for base in cls.__mro__[1:-1]: + if "__table__" in base.__dict__: + break + else: + return sa.Table(*args, **kwargs) + + # Single-table inheritance, use the parent table name. __init__ will unset + # __table__ based on this. + if "__tablename__" in cls.__dict__: + del cls.__tablename__ + + return None + + +def should_set_tablename(cls: type) -> bool: + """Determine whether ``__tablename__`` should be generated for a model. + + - If no class in the MRO sets a name, one should be generated. + - If a declared attr is found, it should be used instead. + - If a name is found, it should be used if the class is a mixin, otherwise one + should be generated. + - Abstract models should not have one generated. + + Later, ``__table_cls__`` will determine if the model looks like single or + joined-table inheritance. If no primary key is found, the name will be unset. + """ + if cls.__dict__.get("__abstract__", False) or not any( + isinstance(b, sa.orm.DeclarativeMeta) for b in cls.__mro__[1:] + ): + return False + + for base in cls.__mro__: + if "__tablename__" not in base.__dict__: + continue + + if isinstance(base.__dict__["__tablename__"], sa.orm.declared_attr): + return False + + return not ( + base is cls + or base.__dict__.get("__abstract__", False) + or not isinstance(base, sa.orm.DeclarativeMeta) + ) + + return True + + +def camel_to_snake_case(name: str) -> str: + """Convert a ``CamelCase`` name to ``snake_case``.""" + name = re.sub(r"((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))", r"_\1", name) + return name.lower().lstrip("_") + + +class DefaultMeta(BindMetaMixin, NameMetaMixin, sa.orm.DeclarativeMeta): + """SQLAlchemy declarative metaclass that provides ``__bind_key__`` and + ``__tablename__`` support. + """ diff --git a/.venv/Lib/site-packages/flask_sqlalchemy/pagination.py b/.venv/Lib/site-packages/flask_sqlalchemy/pagination.py new file mode 100644 index 000000000..8781bec8b --- /dev/null +++ b/.venv/Lib/site-packages/flask_sqlalchemy/pagination.py @@ -0,0 +1,360 @@ +from __future__ import annotations + +import typing as t +from math import ceil + +import sqlalchemy as sa +import sqlalchemy.orm +from flask import abort +from flask import request + + +class Pagination: + """Apply an offset and limit to the query based on the current page and number of + items per page. + + Don't create pagination objects manually. They are created by + :meth:`.SQLAlchemy.paginate` and :meth:`.Query.paginate`. + + This is a base class, a subclass must implement :meth:`_query_items` and + :meth:`_query_count`. Those methods will use arguments passed as ``kwargs`` to + perform the queries. + + :param page: The current page, used to calculate the offset. Defaults to the + ``page`` query arg during a request, or 1 otherwise. + :param per_page: The maximum number of items on a page, used to calculate the + offset and limit. Defaults to the ``per_page`` query arg during a request, + or 20 otherwise. + :param max_per_page: The maximum allowed value for ``per_page``, to limit a + user-provided value. Use ``None`` for no limit. Defaults to 100. + :param error_out: Abort with a ``404 Not Found`` error if no items are returned + and ``page`` is not 1, or if ``page`` or ``per_page`` is less than 1, or if + either are not ints. + :param count: Calculate the total number of values by issuing an extra count + query. For very complex queries this may be inaccurate or slow, so it can be + disabled and set manually if necessary. + :param kwargs: Information about the query to paginate. Different subclasses will + require different arguments. + + .. versionchanged:: 3.0 + Iterating over a pagination object iterates over its items. + + .. versionchanged:: 3.0 + Creating instances manually is not a public API. + """ + + def __init__( + self, + page: int | None = None, + per_page: int | None = None, + max_per_page: int | None = 100, + error_out: bool = True, + count: bool = True, + **kwargs: t.Any, + ) -> None: + self._query_args = kwargs + page, per_page = self._prepare_page_args( + page=page, + per_page=per_page, + max_per_page=max_per_page, + error_out=error_out, + ) + + self.page: int = page + """The current page.""" + + self.per_page: int = per_page + """The maximum number of items on a page.""" + + items = self._query_items() + + if not items and page != 1 and error_out: + abort(404) + + self.items: list[t.Any] = items + """The items on the current page. Iterating over the pagination object is + equivalent to iterating over the items. + """ + + if count: + total = self._query_count() + else: + total = None + + self.total: int | None = total + """The total number of items across all pages.""" + + @staticmethod + def _prepare_page_args( + *, + page: int | None = None, + per_page: int | None = None, + max_per_page: int | None = None, + error_out: bool = True, + ) -> tuple[int, int]: + if request: + if page is None: + try: + page = int(request.args.get("page", 1)) + except (TypeError, ValueError): + if error_out: + abort(404) + + page = 1 + + if per_page is None: + try: + per_page = int(request.args.get("per_page", 20)) + except (TypeError, ValueError): + if error_out: + abort(404) + + per_page = 20 + else: + if page is None: + page = 1 + + if per_page is None: + per_page = 20 + + if max_per_page is not None: + per_page = min(per_page, max_per_page) + + if page < 1: + if error_out: + abort(404) + else: + page = 1 + + if per_page < 1: + if error_out: + abort(404) + else: + per_page = 20 + + return page, per_page + + @property + def _query_offset(self) -> int: + """The index of the first item to query, passed to ``offset()``. + + :meta private: + + .. versionadded:: 3.0 + """ + return (self.page - 1) * self.per_page + + def _query_items(self) -> list[t.Any]: + """Execute the query to get the items on the current page. + + Uses init arguments stored in :attr:`_query_args`. + + :meta private: + + .. versionadded:: 3.0 + """ + raise NotImplementedError + + def _query_count(self) -> int: + """Execute the query to get the total number of items. + + Uses init arguments stored in :attr:`_query_args`. + + :meta private: + + .. versionadded:: 3.0 + """ + raise NotImplementedError + + @property + def first(self) -> int: + """The number of the first item on the page, starting from 1, or 0 if there are + no items. + + .. versionadded:: 3.0 + """ + if len(self.items) == 0: + return 0 + + return (self.page - 1) * self.per_page + 1 + + @property + def last(self) -> int: + """The number of the last item on the page, starting from 1, inclusive, or 0 if + there are no items. + + .. versionadded:: 3.0 + """ + first = self.first + return max(first, first + len(self.items) - 1) + + @property + def pages(self) -> int: + """The total number of pages.""" + if self.total == 0 or self.total is None: + return 0 + + return ceil(self.total / self.per_page) + + @property + def has_prev(self) -> bool: + """``True`` if this is not the first page.""" + return self.page > 1 + + @property + def prev_num(self) -> int | None: + """The previous page number, or ``None`` if this is the first page.""" + if not self.has_prev: + return None + + return self.page - 1 + + def prev(self, *, error_out: bool = False) -> Pagination: + """Query the :class:`Pagination` object for the previous page. + + :param error_out: Abort with a ``404 Not Found`` error if no items are returned + and ``page`` is not 1, or if ``page`` or ``per_page`` is less than 1, or if + either are not ints. + """ + p = type(self)( + page=self.page - 1, + per_page=self.per_page, + error_out=error_out, + count=False, + **self._query_args, + ) + p.total = self.total + return p + + @property + def has_next(self) -> bool: + """``True`` if this is not the last page.""" + return self.page < self.pages + + @property + def next_num(self) -> int | None: + """The next page number, or ``None`` if this is the last page.""" + if not self.has_next: + return None + + return self.page + 1 + + def next(self, *, error_out: bool = False) -> Pagination: + """Query the :class:`Pagination` object for the next page. + + :param error_out: Abort with a ``404 Not Found`` error if no items are returned + and ``page`` is not 1, or if ``page`` or ``per_page`` is less than 1, or if + either are not ints. + """ + p = type(self)( + page=self.page + 1, + per_page=self.per_page, + error_out=error_out, + count=False, + **self._query_args, + ) + p.total = self.total + return p + + def iter_pages( + self, + *, + left_edge: int = 2, + left_current: int = 2, + right_current: int = 4, + right_edge: int = 2, + ) -> t.Iterator[int | None]: + """Yield page numbers for a pagination widget. Skipped pages between the edges + and middle are represented by a ``None``. + + For example, if there are 20 pages and the current page is 7, the following + values are yielded. + + .. code-block:: python + + 1, 2, None, 5, 6, 7, 8, 9, 10, 11, None, 19, 20 + + :param left_edge: How many pages to show from the first page. + :param left_current: How many pages to show left of the current page. + :param right_current: How many pages to show right of the current page. + :param right_edge: How many pages to show from the last page. + + .. versionchanged:: 3.0 + Improved efficiency of calculating what to yield. + + .. versionchanged:: 3.0 + ``right_current`` boundary is inclusive. + + .. versionchanged:: 3.0 + All parameters are keyword-only. + """ + pages_end = self.pages + 1 + + if pages_end == 1: + return + + left_end = min(1 + left_edge, pages_end) + yield from range(1, left_end) + + if left_end == pages_end: + return + + mid_start = max(left_end, self.page - left_current) + mid_end = min(self.page + right_current + 1, pages_end) + + if mid_start - left_end > 0: + yield None + + yield from range(mid_start, mid_end) + + if mid_end == pages_end: + return + + right_start = max(mid_end, pages_end - right_edge) + + if right_start - mid_end > 0: + yield None + + yield from range(right_start, pages_end) + + def __iter__(self) -> t.Iterator[t.Any]: + yield from self.items + + +class SelectPagination(Pagination): + """Returned by :meth:`.SQLAlchemy.paginate`. Takes ``select`` and ``session`` + arguments in addition to the :class:`Pagination` arguments. + + .. versionadded:: 3.0 + """ + + def _query_items(self) -> list[t.Any]: + select = self._query_args["select"] + select = select.limit(self.per_page).offset(self._query_offset) + session = self._query_args["session"] + return list(session.execute(select).unique().scalars()) + + def _query_count(self) -> int: + select = self._query_args["select"] + sub = select.options(sa.orm.lazyload("*")).order_by(None).subquery() + session = self._query_args["session"] + out = session.execute(sa.select(sa.func.count()).select_from(sub)).scalar() + return out # type: ignore[no-any-return] + + +class QueryPagination(Pagination): + """Returned by :meth:`.Query.paginate`. Takes a ``query`` argument in addition to + the :class:`Pagination` arguments. + + .. versionadded:: 3.0 + """ + + def _query_items(self) -> list[t.Any]: + query = self._query_args["query"] + out = query.limit(self.per_page).offset(self._query_offset).all() + return out # type: ignore[no-any-return] + + def _query_count(self) -> int: + # Query.count automatically disables eager loads + out = self._query_args["query"].order_by(None).count() + return out # type: ignore[no-any-return] diff --git a/.venv/Lib/site-packages/flask_sqlalchemy/py.typed b/.venv/Lib/site-packages/flask_sqlalchemy/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/.venv/Lib/site-packages/flask_sqlalchemy/query.py b/.venv/Lib/site-packages/flask_sqlalchemy/query.py new file mode 100644 index 000000000..4b8c7d1de --- /dev/null +++ b/.venv/Lib/site-packages/flask_sqlalchemy/query.py @@ -0,0 +1,106 @@ +from __future__ import annotations + +import typing as t + +import sqlalchemy as sa +import sqlalchemy.exc +import sqlalchemy.orm +from flask import abort + +from .pagination import Pagination +from .pagination import QueryPagination + + +class Query(sa.orm.Query): # type: ignore[type-arg] + """SQLAlchemy :class:`~sqlalchemy.orm.query.Query` subclass with some extra methods + useful for querying in a web application. + + This is the default query class for :attr:`.Model.query`. + + .. versionchanged:: 3.0 + Renamed to ``Query`` from ``BaseQuery``. + """ + + def get_or_404(self, ident: t.Any, description: str | None = None) -> t.Any: + """Like :meth:`~sqlalchemy.orm.Query.get` but aborts with a ``404 Not Found`` + error instead of returning ``None``. + + :param ident: The primary key to query. + :param description: A custom message to show on the error page. + """ + rv = self.get(ident) + + if rv is None: + abort(404, description=description) + + return rv + + def first_or_404(self, description: str | None = None) -> t.Any: + """Like :meth:`~sqlalchemy.orm.Query.first` but aborts with a ``404 Not Found`` + error instead of returning ``None``. + + :param description: A custom message to show on the error page. + """ + rv = self.first() + + if rv is None: + abort(404, description=description) + + return rv + + def one_or_404(self, description: str | None = None) -> t.Any: + """Like :meth:`~sqlalchemy.orm.Query.one` but aborts with a ``404 Not Found`` + error instead of raising ``NoResultFound`` or ``MultipleResultsFound``. + + :param description: A custom message to show on the error page. + + .. versionadded:: 3.0 + """ + try: + return self.one() + except (sa.exc.NoResultFound, sa.exc.MultipleResultsFound): + abort(404, description=description) + + def paginate( + self, + *, + page: int | None = None, + per_page: int | None = None, + max_per_page: int | None = None, + error_out: bool = True, + count: bool = True, + ) -> Pagination: + """Apply an offset and limit to the query based on the current page and number + of items per page, returning a :class:`.Pagination` object. + + :param page: The current page, used to calculate the offset. Defaults to the + ``page`` query arg during a request, or 1 otherwise. + :param per_page: The maximum number of items on a page, used to calculate the + offset and limit. Defaults to the ``per_page`` query arg during a request, + or 20 otherwise. + :param max_per_page: The maximum allowed value for ``per_page``, to limit a + user-provided value. Use ``None`` for no limit. Defaults to 100. + :param error_out: Abort with a ``404 Not Found`` error if no items are returned + and ``page`` is not 1, or if ``page`` or ``per_page`` is less than 1, or if + either are not ints. + :param count: Calculate the total number of values by issuing an extra count + query. For very complex queries this may be inaccurate or slow, so it can be + disabled and set manually if necessary. + + .. versionchanged:: 3.0 + All parameters are keyword-only. + + .. versionchanged:: 3.0 + The ``count`` query is more efficient. + + .. versionchanged:: 3.0 + ``max_per_page`` defaults to 100. + """ + return QueryPagination( + query=self, + page=page, + per_page=per_page, + max_per_page=max_per_page, + error_out=error_out, + count=count, + ) diff --git a/.venv/Lib/site-packages/flask_sqlalchemy/record_queries.py b/.venv/Lib/site-packages/flask_sqlalchemy/record_queries.py new file mode 100644 index 000000000..e3d7cc209 --- /dev/null +++ b/.venv/Lib/site-packages/flask_sqlalchemy/record_queries.py @@ -0,0 +1,141 @@ +from __future__ import annotations + +import dataclasses +import inspect +import typing as t +from time import perf_counter + +import sqlalchemy as sa +import sqlalchemy.event +from flask import current_app +from flask import g +from flask import has_app_context + + +def get_recorded_queries() -> list[_QueryInfo]: + """Get the list of recorded query information for the current session. Queries are + recorded if the config :data:`.SQLALCHEMY_RECORD_QUERIES` is enabled. + + Each query info object has the following attributes: + + ``statement`` + The string of SQL generated by SQLAlchemy with parameter placeholders. + ``parameters`` + The parameters sent with the SQL statement. + ``start_time`` / ``end_time`` + Timing info about when the query started execution and when the results where + returned. Accuracy and value depends on the operating system. + ``duration`` + The time the query took in seconds. + ``location`` + A string description of where in your application code the query was executed. + This may not be possible to calculate, and the format is not stable. + + .. versionchanged:: 3.0 + Renamed from ``get_debug_queries``. + + .. versionchanged:: 3.0 + The info object is a dataclass instead of a tuple. + + .. versionchanged:: 3.0 + The info object attribute ``context`` is renamed to ``location``. + + .. versionchanged:: 3.0 + Not enabled automatically in debug or testing mode. + """ + return g.get("_sqlalchemy_queries", []) # type: ignore[no-any-return] + + +@dataclasses.dataclass +class _QueryInfo: + """Information about an executed query. Returned by :func:`get_recorded_queries`. + + .. versionchanged:: 3.0 + Renamed from ``_DebugQueryTuple``. + + .. versionchanged:: 3.0 + Changed to a dataclass instead of a tuple. + + .. versionchanged:: 3.0 + ``context`` is renamed to ``location``. + """ + + statement: str | None + parameters: t.Any + start_time: float + end_time: float + location: str + + @property + def duration(self) -> float: + return self.end_time - self.start_time + + @property + def context(self) -> str: + import warnings + + warnings.warn( + "'context' is renamed to 'location'. The old name is deprecated and will be" + " removed in Flask-SQLAlchemy 3.1.", + DeprecationWarning, + stacklevel=2, + ) + return self.location + + def __getitem__(self, key: int) -> object: + import warnings + + name = ("statement", "parameters", "start_time", "end_time", "location")[key] + warnings.warn( + "Query info is a dataclass, not a tuple. Lookup by index is deprecated and" + f" will be removed in Flask-SQLAlchemy 3.1. Use 'info.{name}' instead.", + DeprecationWarning, + stacklevel=2, + ) + return getattr(self, name) + + +def _listen(engine: sa.engine.Engine) -> None: + sa.event.listen(engine, "before_cursor_execute", _record_start, named=True) + sa.event.listen(engine, "after_cursor_execute", _record_end, named=True) + + +def _record_start(context: sa.engine.ExecutionContext, **kwargs: t.Any) -> None: + if not has_app_context(): + return + + context._fsa_start_time = perf_counter() # type: ignore[attr-defined] + + +def _record_end(context: sa.engine.ExecutionContext, **kwargs: t.Any) -> None: + if not has_app_context(): + return + + if "_sqlalchemy_queries" not in g: + g._sqlalchemy_queries = [] + + import_top = current_app.import_name.partition(".")[0] + import_dot = f"{import_top}." + frame = inspect.currentframe() + + while frame: + name = frame.f_globals.get("__name__") + + if name and (name == import_top or name.startswith(import_dot)): + code = frame.f_code + location = f"{code.co_filename}:{frame.f_lineno} ({code.co_name})" + break + + frame = frame.f_back + else: + location = "" + + g._sqlalchemy_queries.append( + _QueryInfo( + statement=context.statement, + parameters=context.parameters, + start_time=context._fsa_start_time, # type: ignore[attr-defined] + end_time=perf_counter(), + location=location, + ) + ) diff --git a/.venv/Lib/site-packages/flask_sqlalchemy/session.py b/.venv/Lib/site-packages/flask_sqlalchemy/session.py new file mode 100644 index 000000000..e50c2926c --- /dev/null +++ b/.venv/Lib/site-packages/flask_sqlalchemy/session.py @@ -0,0 +1,102 @@ +from __future__ import annotations + +import typing as t + +import sqlalchemy as sa +import sqlalchemy.exc +import sqlalchemy.orm +from flask.globals import app_ctx + +if t.TYPE_CHECKING: + from .extension import SQLAlchemy + + +class Session(sa.orm.Session): + """A SQLAlchemy :class:`~sqlalchemy.orm.Session` class that chooses what engine to + use based on the bind key associated with the metadata associated with the thing + being queried. + + To customize ``db.session``, subclass this and pass it as the ``class_`` key in the + ``session_options`` to :class:`.SQLAlchemy`. + + .. versionchanged:: 3.0 + Renamed from ``SignallingSession``. + """ + + def __init__(self, db: SQLAlchemy, **kwargs: t.Any) -> None: + super().__init__(**kwargs) + self._db = db + self._model_changes: dict[object, tuple[t.Any, str]] = {} + + def get_bind( + self, + mapper: t.Any | None = None, + clause: t.Any | None = None, + bind: sa.engine.Engine | sa.engine.Connection | None = None, + **kwargs: t.Any, + ) -> sa.engine.Engine | sa.engine.Connection: + """Select an engine based on the ``bind_key`` of the metadata associated with + the model or table being queried. If no bind key is set, uses the default bind. + + .. versionchanged:: 3.0.3 + Fix finding the bind for a joined inheritance model. + + .. versionchanged:: 3.0 + The implementation more closely matches the base SQLAlchemy implementation. + + .. versionchanged:: 2.1 + Support joining an external transaction. + """ + if bind is not None: + return bind + + engines = self._db.engines + + if mapper is not None: + try: + mapper = sa.inspect(mapper) + except sa.exc.NoInspectionAvailable as e: + if isinstance(mapper, type): + raise sa.orm.exc.UnmappedClassError(mapper) from e + + raise + + engine = _clause_to_engine(mapper.local_table, engines) + + if engine is not None: + return engine + + if clause is not None: + engine = _clause_to_engine(clause, engines) + + if engine is not None: + return engine + + if None in engines: + return engines[None] + + return super().get_bind(mapper=mapper, clause=clause, bind=bind, **kwargs) + + +def _clause_to_engine( + clause: t.Any | None, engines: t.Mapping[str | None, sa.engine.Engine] +) -> sa.engine.Engine | None: + """If the clause is a table, return the engine associated with the table's + metadata's bind key. + """ + if isinstance(clause, sa.Table) and "bind_key" in clause.metadata.info: + key = clause.metadata.info["bind_key"] + + if key not in engines: + raise sa.exc.UnboundExecutionError( + f"Bind key '{key}' is not in 'SQLALCHEMY_BINDS' config." + ) + + return engines[key] + + return None + + +def _app_ctx_id() -> int: + """Get the id of the current Flask application context for the session scope.""" + return id(app_ctx._get_current_object()) # type: ignore[attr-defined] diff --git a/.venv/Lib/site-packages/flask_sqlalchemy/table.py b/.venv/Lib/site-packages/flask_sqlalchemy/table.py new file mode 100644 index 000000000..ab08a692a --- /dev/null +++ b/.venv/Lib/site-packages/flask_sqlalchemy/table.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +import typing as t + +import sqlalchemy as sa +import sqlalchemy.sql.schema as sa_sql_schema + + +class _Table(sa.Table): + @t.overload + def __init__( + self, + name: str, + *args: sa_sql_schema.SchemaItem, + bind_key: str | None = None, + **kwargs: t.Any, + ) -> None: + ... + + @t.overload + def __init__( + self, + name: str, + metadata: sa.MetaData, + *args: sa_sql_schema.SchemaItem, + **kwargs: t.Any, + ) -> None: + ... + + @t.overload + def __init__( + self, name: str, *args: sa_sql_schema.SchemaItem, **kwargs: t.Any + ) -> None: + ... + + def __init__( + self, name: str, *args: sa_sql_schema.SchemaItem, **kwargs: t.Any + ) -> None: + super().__init__(name, *args, **kwargs) # type: ignore[arg-type] diff --git a/.venv/Lib/site-packages/flask_sqlalchemy/track_modifications.py b/.venv/Lib/site-packages/flask_sqlalchemy/track_modifications.py new file mode 100644 index 000000000..c40c1aec4 --- /dev/null +++ b/.venv/Lib/site-packages/flask_sqlalchemy/track_modifications.py @@ -0,0 +1,88 @@ +from __future__ import annotations + +import typing as t + +import sqlalchemy as sa +import sqlalchemy.event +import sqlalchemy.orm +from flask import current_app +from flask import has_app_context +from flask.signals import Namespace # type: ignore[attr-defined] + +if t.TYPE_CHECKING: + from .session import Session + +_signals = Namespace() + +models_committed = _signals.signal("models-committed") +"""This Blinker signal is sent after the session is committed if there were changed +models in the session. + +The sender is the application that emitted the changes. The receiver is passed the +``changes`` argument with a list of tuples in the form ``(instance, operation)``. +The operations are ``"insert"``, ``"update"``, and ``"delete"``. +""" + +before_models_committed = _signals.signal("before-models-committed") +"""This signal works exactly like :data:`models_committed` but is emitted before the +commit takes place. +""" + + +def _listen(session: sa.orm.scoped_session[Session]) -> None: + sa.event.listen(session, "before_flush", _record_ops, named=True) + sa.event.listen(session, "before_commit", _record_ops, named=True) + sa.event.listen(session, "before_commit", _before_commit) + sa.event.listen(session, "after_commit", _after_commit) + sa.event.listen(session, "after_rollback", _after_rollback) + + +def _record_ops(session: Session, **kwargs: t.Any) -> None: + if not has_app_context(): + return + + if not current_app.config["SQLALCHEMY_TRACK_MODIFICATIONS"]: + return + + for targets, operation in ( + (session.new, "insert"), + (session.dirty, "update"), + (session.deleted, "delete"), + ): + for target in targets: + state = sa.inspect(target) + key = state.identity_key if state.has_identity else id(target) + session._model_changes[key] = (target, operation) + + +def _before_commit(session: Session) -> None: + if not has_app_context(): + return + + app = current_app._get_current_object() # type: ignore[attr-defined] + + if not app.config["SQLALCHEMY_TRACK_MODIFICATIONS"]: + return + + if session._model_changes: + changes = list(session._model_changes.values()) + before_models_committed.send(app, changes=changes) + + +def _after_commit(session: Session) -> None: + if not has_app_context(): + return + + app = current_app._get_current_object() # type: ignore[attr-defined] + + if not app.config["SQLALCHEMY_TRACK_MODIFICATIONS"]: + return + + if session._model_changes: + changes = list(session._model_changes.values()) + models_committed.send(app, changes=changes) + session._model_changes.clear() + + +def _after_rollback(session: Session) -> None: + session._model_changes.clear() diff --git a/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/AUTHORS b/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/AUTHORS new file mode 100644 index 000000000..42a5c227b --- /dev/null +++ b/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/AUTHORS @@ -0,0 +1,51 @@ +Original Authors +---------------- +* Armin Rigo +* Christian Tismer + +Contributors +------------ +* Al Stone +* Alexander Schmidt +* Alexey Borzenkov +* Andreas Schwab +* Armin Ronacher +* Bin Wang +* Bob Ippolito +* ChangBo Guo +* Christoph Gohlke +* Denis Bilenko +* Dirk Mueller +* Donovan Preston +* Fantix King +* Floris Bruynooghe +* Fredrik Fornwall +* Gerd Woetzel +* Giel van Schijndel +* Gökhan Karabulut +* Gustavo Niemeyer +* Guy Rozendorn +* Hye-Shik Chang +* Jared Kuolt +* Jason Madden +* Josh Snyder +* Kyle Ambroff +* Laszlo Boszormenyi +* Mao Han +* Marc Abramowitz +* Marc Schlaich +* Marcin Bachry +* Matt Madison +* Matt Turner +* Michael Ellerman +* Michael Matz +* Ralf Schmitt +* Robie Basak +* Ronny Pfannschmidt +* Samual M. Rushing +* Tony Bowles +* Tony Breeds +* Trevor Bowen +* Tulio Magno Quites Machado Filho +* Ulrich Weigand +* Victor Stinner diff --git a/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/INSTALLER b/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/LICENSE b/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/LICENSE new file mode 100644 index 000000000..b73a4a10c --- /dev/null +++ b/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/LICENSE @@ -0,0 +1,30 @@ +The following files are derived from Stackless Python and are subject to the +same license as Stackless Python: + + src/greenlet/slp_platformselect.h + files in src/greenlet/platform/ directory + +See LICENSE.PSF and http://www.stackless.com/ for details. + +Unless otherwise noted, the files in greenlet have been released under the +following MIT license: + +Copyright (c) Armin Rigo, Christian Tismer and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/LICENSE.PSF b/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/LICENSE.PSF new file mode 100644 index 000000000..d3b509a2b --- /dev/null +++ b/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/LICENSE.PSF @@ -0,0 +1,47 @@ +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011 Python Software Foundation; All Rights Reserved" are retained in Python +alone or in any derivative version prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. diff --git a/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/METADATA b/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/METADATA new file mode 100644 index 000000000..2100a3e72 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/METADATA @@ -0,0 +1,106 @@ +Metadata-Version: 2.1 +Name: greenlet +Version: 2.0.2 +Summary: Lightweight in-process concurrent programming +Home-page: https://greenlet.readthedocs.io/ +Author: Alexey Borzenkov +Author-email: snaury@gmail.com +Maintainer: Jason Madden +Maintainer-email: jason@seecoresoftware.com +License: MIT License +Project-URL: Bug Tracker, https://github.com/python-greenlet/greenlet/issues +Project-URL: Source Code, https://github.com/python-greenlet/greenlet/ +Project-URL: Documentation, https://greenlet.readthedocs.io/ +Keywords: greenlet coroutine concurrency threads cooperative +Platform: any +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Natural Language :: English +Classifier: Programming Language :: C +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Operating System :: OS Independent +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.* +Description-Content-Type: text/x-rst +License-File: LICENSE +License-File: LICENSE.PSF +License-File: AUTHORS +Provides-Extra: docs +Requires-Dist: Sphinx ; extra == 'docs' +Requires-Dist: docutils (<0.18) ; (python_version < "3") and extra == 'docs' +Provides-Extra: test +Requires-Dist: objgraph ; extra == 'test' +Requires-Dist: psutil ; extra == 'test' + +.. This file is included into docs/history.rst + +.. image:: https://github.com/python-greenlet/greenlet/workflows/tests/badge.svg + :target: https://github.com/python-greenlet/greenlet/actions + +Greenlets are lightweight coroutines for in-process concurrent +programming. + +The "greenlet" package is a spin-off of `Stackless`_, a version of +CPython that supports micro-threads called "tasklets". Tasklets run +pseudo-concurrently (typically in a single or a few OS-level threads) +and are synchronized with data exchanges on "channels". + +A "greenlet", on the other hand, is a still more primitive notion of +micro-thread with no implicit scheduling; coroutines, in other words. +This is useful when you want to control exactly when your code runs. +You can build custom scheduled micro-threads on top of greenlet; +however, it seems that greenlets are useful on their own as a way to +make advanced control flow structures. For example, we can recreate +generators; the difference with Python's own generators is that our +generators can call nested functions and the nested functions can +yield values too. (Additionally, you don't need a "yield" keyword. See +the example in `test_generator.py +`_). + +Greenlets are provided as a C extension module for the regular unmodified +interpreter. + +.. _`Stackless`: http://www.stackless.com + + +Who is using Greenlet? +====================== + +There are several libraries that use Greenlet as a more flexible +alternative to Python's built in coroutine support: + + - `Concurrence`_ + - `Eventlet`_ + - `Gevent`_ + +.. _Concurrence: http://opensource.hyves.org/concurrence/ +.. _Eventlet: http://eventlet.net/ +.. _Gevent: http://www.gevent.org/ + +Getting Greenlet +================ + +The easiest way to get Greenlet is to install it with pip:: + + pip install greenlet + + +Source code archives and binary distributions are available on the +python package index at https://pypi.org/project/greenlet + +The source code repository is hosted on github: +https://github.com/python-greenlet/greenlet + +Documentation is available on readthedocs.org: +https://greenlet.readthedocs.io diff --git a/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/RECORD b/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/RECORD new file mode 100644 index 000000000..42564ddcd --- /dev/null +++ b/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/RECORD @@ -0,0 +1,91 @@ +../../include/site/python3.11/greenlet/greenlet.h,sha256=sz5pYRSQqedgOt2AMgxLZdTjO-qcr_JMvgiEJR9IAJ8,4755 +greenlet-2.0.2.dist-info/AUTHORS,sha256=swW28t2knVRxRkaEQNZtO7MP9Sgnompb7B6cNgJM8Gk,849 +greenlet-2.0.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +greenlet-2.0.2.dist-info/LICENSE,sha256=dpgx1uXfrywggC-sz_H6-0wgJd2PYlPfpH_K1Z1NCXk,1434 +greenlet-2.0.2.dist-info/LICENSE.PSF,sha256=5f88I8EQ5JTNfXNsEP2W1GJFe6_soxCEDbZScpjH1Gs,2424 +greenlet-2.0.2.dist-info/METADATA,sha256=SpwOHmf5gTdOk2LYzvER6a4TqEE2xbR-WLbnFHgGM4k,4200 +greenlet-2.0.2.dist-info/RECORD,, +greenlet-2.0.2.dist-info/WHEEL,sha256=wklNeoByNLhdCl-oEQTdaHIeDl4q9zaQVqAlPxUEgLU,102 +greenlet-2.0.2.dist-info/top_level.txt,sha256=YSnRsCRoO61JGlP57o8iKL6rdLWDWuiyKD8ekpWUsDc,9 +greenlet/__init__.py,sha256=0uLqzJsY24W1VZgMSvKDRr7H3lIAajRNvjeDjenhwg8,1723 +greenlet/__pycache__/__init__.cpython-311.pyc,, +greenlet/_greenlet.cp311-win_amd64.pyd,sha256=NLSj2fzeSq-Mnx2eV44zDcoAiZx2KEhq6HuyAKlDBAM,64512 +greenlet/greenlet.cpp,sha256=edwdXy3KBU7RnjO7BXfQ-OUMrjSTuPEH7dk07dGjd9c,110159 +greenlet/greenlet.h,sha256=sz5pYRSQqedgOt2AMgxLZdTjO-qcr_JMvgiEJR9IAJ8,4755 +greenlet/greenlet_allocator.hpp,sha256=kxyWW4Qdwlrc7ufgdb5vd6Y7jhauQ699Kod0mqiO1iM,1582 +greenlet/greenlet_compiler_compat.hpp,sha256=c-z5dQNEyja6Wos4-umxsFQ04_MPRSneOZAGyDCwHs4,5446 +greenlet/greenlet_cpython_compat.hpp,sha256=6TYeFAhuLQQ33FS3Ndun35W7oyARqcUwYdleRsysfqg,4806 +greenlet/greenlet_exceptions.hpp,sha256=FiWMqW8Aj6RedcmNDUk7dVd5T9HIdLgL-DREOyZ0new,2307 +greenlet/greenlet_greenlet.hpp,sha256=k7Z2HNmGckPoXbpEbP9L9hvecQ32SuP7oFGDwwSdHME,41611 +greenlet/greenlet_internal.hpp,sha256=bfIjQ4gXFtk7mJt9xcPnWholXa1FxL6Q5ip-lWbrhjI,2707 +greenlet/greenlet_refs.hpp,sha256=x117iO59IolyQ_rTwP_xW66TW_Q2D_jqbQJtmD0N6H0,32906 +greenlet/greenlet_slp_switch.hpp,sha256=dGtzhCBzsVI0b9KCHulv8X7kXjasZ7KCrKYxFB-fewY,3987 +greenlet/greenlet_thread_state.hpp,sha256=vzRx-RdlhDQIfsi_uitvd6Mudb3_3F5Mzxi0Cs7vuuU,21075 +greenlet/greenlet_thread_state_dict_cleanup.hpp,sha256=tEN0rI1pZiEsdtr7Oda24gr52fGiHnYTLyM8Vme3Gns,3831 +greenlet/greenlet_thread_support.hpp,sha256=ZI5Ye4842cGDyUo8aVKM2FQ_jWs7Pj0cR27Nxx1IY6s,4126 +greenlet/platform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +greenlet/platform/__pycache__/__init__.cpython-311.pyc,, +greenlet/platform/setup_switch_x64_masm.cmd,sha256=ZpClUJeU0ujEPSTWNSepP0W2f9XiYQKA8QKSoVou8EU,143 +greenlet/platform/switch_aarch64_gcc.h,sha256=J89BnU496h11g99DXl1DYnZXwdZAb2bK0g3AZ8BSQgY,2683 +greenlet/platform/switch_alpha_unix.h,sha256=T6kOBiHy3hLmy1vrmFrxbnOnRu0EJkoG_yuWy7fykZ4,689 +greenlet/platform/switch_amd64_unix.h,sha256=EcSFCBlodEBhqhKjcJqY_5Dn_jn7pKpkJlOvp7gFXLI,2748 +greenlet/platform/switch_arm32_gcc.h,sha256=wflI2cGZBfLzM_GGgYx3OrFeoOq7OTsJP53dKLsrxS0,2488 +greenlet/platform/switch_arm32_ios.h,sha256=yQZXCa0AZbyAIS9tKceyTCrRYlihpFBKDbiPCn_3im0,1901 +greenlet/platform/switch_arm64_masm.asm,sha256=4kpTtfy7rfcr8j1CpJLAK21EtZpGDAJXWRU68HEy5A8,1245 +greenlet/platform/switch_arm64_masm.obj,sha256=DmLnIB_icoEHAz1naue_pJPTZgR9ElM7-Nmztr-o9_U,746 +greenlet/platform/switch_arm64_msvc.h,sha256=RqK5MHLmXI3Q-FQ7tm32KWnbDNZKnkJdq8CR89cz640,398 +greenlet/platform/switch_csky_gcc.h,sha256=GHlaVXrzQuSkrDqgL7-Ji9YwZnprpFhjPznNyp0NnvU,1340 +greenlet/platform/switch_m68k_gcc.h,sha256=VSa6NpZhvyyvF-Q58CTIWSpEDo4FKygOyTz00whctlw,928 +greenlet/platform/switch_mips_unix.h,sha256=9ptMGEBXafee15RxOm5NrxiC2bEnwM9AkxJ7ktVatU8,1444 +greenlet/platform/switch_ppc64_aix.h,sha256=ADpifLPlr6pTdT76bt6ozcqPjHrfPsJ93lQfc1VNaug,3878 +greenlet/platform/switch_ppc64_linux.h,sha256=jqPKpTg09FzmCn59Kt6OJi2-40aoazFVJcf1YETLlwA,3833 +greenlet/platform/switch_ppc_aix.h,sha256=nClVVlsRlFAI-I3fmivSJyJK7Xzx3_8l3Wf8QNJ9FMU,2959 +greenlet/platform/switch_ppc_linux.h,sha256=J4eKMA73WbPYSaq0yAedzHB6J6ZKE8tIIzkqYxlaA2c,2777 +greenlet/platform/switch_ppc_macosx.h,sha256=bnL2MqIUm9--NHizb5NYijvSrqutvuJx4auYCdqXllM,2642 +greenlet/platform/switch_ppc_unix.h,sha256=5UW9c71NGJh6xksEbAOButBFH168QRyZ5O53yXdXGxg,2670 +greenlet/platform/switch_riscv_unix.h,sha256=jX3vC_xZXiUho8tz4J6Ai8BNQB80yLn03fxkoMztVCU,740 +greenlet/platform/switch_s390_unix.h,sha256=9oJkYnyUovPvXOAsVLXoj-Unl_Rr_DidkXYMaRXLS0w,2781 +greenlet/platform/switch_sparc_sun_gcc.h,sha256=0vHXNNCdz-1ioQsw-OtK0ridnBVIzErYWiK7bBu6OgM,2815 +greenlet/platform/switch_x32_unix.h,sha256=ie7Nxo6Cf_x4UVOSA_a3bJYPlRKZ1BvLWsclyQle_SY,1527 +greenlet/platform/switch_x64_masm.asm,sha256=nu6n2sWyXuXfpPx40d9YmLfHXUc1sHgeTvX1kUzuvEM,1841 +greenlet/platform/switch_x64_masm.obj,sha256=GNtTNxYdo7idFUYsQv-mrXWgyT5EJ93-9q90lN6svtQ,1078 +greenlet/platform/switch_x64_msvc.h,sha256=LIeasyKo_vHzspdMzMHbosRhrBfKI4BkQOh4qcTHyJw,1805 +greenlet/platform/switch_x86_msvc.h,sha256=TtGOwinbFfnn6clxMNkCz8i6OmgB6kVRrShoF5iT9to,12838 +greenlet/platform/switch_x86_unix.h,sha256=WvY2sNMFIEfoFVNVakl-osygJui3pSnlVj5jBrdaU08,3068 +greenlet/slp_platformselect.h,sha256=t4Yy9Eb0zO1Qhu9RsRj1YLoIueNAOywrHGZZbeuFz64,3280 +greenlet/tests/__init__.py,sha256=Qo3bLZpIWxq-tqpRVLql1O_tOMjK-ROknGPXhMTAt0g,4976 +greenlet/tests/__pycache__/__init__.cpython-311.pyc,, +greenlet/tests/__pycache__/leakcheck.cpython-311.pyc,, +greenlet/tests/__pycache__/test_contextvars.cpython-311.pyc,, +greenlet/tests/__pycache__/test_cpp.cpython-311.pyc,, +greenlet/tests/__pycache__/test_extension_interface.cpython-311.pyc,, +greenlet/tests/__pycache__/test_gc.cpython-311.pyc,, +greenlet/tests/__pycache__/test_generator.cpython-311.pyc,, +greenlet/tests/__pycache__/test_generator_nested.cpython-311.pyc,, +greenlet/tests/__pycache__/test_greenlet.cpython-311.pyc,, +greenlet/tests/__pycache__/test_greenlet_trash.cpython-311.pyc,, +greenlet/tests/__pycache__/test_leaks.cpython-311.pyc,, +greenlet/tests/__pycache__/test_stack_saved.cpython-311.pyc,, +greenlet/tests/__pycache__/test_throw.cpython-311.pyc,, +greenlet/tests/__pycache__/test_tracing.cpython-311.pyc,, +greenlet/tests/__pycache__/test_version.cpython-311.pyc,, +greenlet/tests/__pycache__/test_weakref.cpython-311.pyc,, +greenlet/tests/_test_extension.c,sha256=py-Rg7fRdAMNwpxgoHDzf5PeT1-h3iZ_xpGBVcmzu4M,6017 +greenlet/tests/_test_extension.cp311-win_amd64.pyd,sha256=YSZajMYSBwo2jUeTtn6879jJj1IaxtGfqh798wCG5JY,13312 +greenlet/tests/_test_extension_cpp.cp311-win_amd64.pyd,sha256=8InkJnupD--2x4I5uEk1J_GakH1rNa3kCUUFmJZDCZc,13824 +greenlet/tests/_test_extension_cpp.cpp,sha256=hUEUj8zBCbOc6jBYLYooAz_rEUtZd1U-lv6ykyd3BZY,5639 +greenlet/tests/leakcheck.py,sha256=SgPOQ5_vttOiLDsCOV6wXvvXRxy6noNHqEwctTC5Vpc,11929 +greenlet/tests/test_contextvars.py,sha256=2fRW58UnSPilM6oWkpKPiQjt2Nt7GX3S1TTSlIWg1qE,10240 +greenlet/tests/test_cpp.py,sha256=kDyP_aEFWgihbGwHoYEbDckez_ceh0pfNNl0cWD5C6s,2963 +greenlet/tests/test_extension_interface.py,sha256=eJ3cwLacdK2WbsrC-4DgeyHdwLRcG4zx7rrkRtqSzC4,3829 +greenlet/tests/test_gc.py,sha256=nf4pgF0eUz8tUYQGPHRPWQZPslztN-FfxvD4EONIpmw,2916 +greenlet/tests/test_generator.py,sha256=tONXiTf98VGm347o1b-810daPiwdla5cbpFg6QI1R1g,1240 +greenlet/tests/test_generator_nested.py,sha256=gMTDwBb5Rx4UcuYYp31YufLONLXruVDaCcKlJ4UIk64,3720 +greenlet/tests/test_greenlet.py,sha256=8HV85AKGTGOEYOcEeYRodWInLamjQIVz0SY8sD0o7ZQ,37747 +greenlet/tests/test_greenlet_trash.py,sha256=e-1l_mexXRpIYpwYvOPqXjzmE9oI0BXMRpT3ywWP-Bw,7683 +greenlet/tests/test_leaks.py,sha256=yx57dXe1wLB_NMinIvIDKRnUj-g6YDytox3Vkx1LXTE,17683 +greenlet/tests/test_stack_saved.py,sha256=eyzqNY2VCGuGlxhT_In6TvZ6Okb0AXFZVyBEnK1jDwA,446 +greenlet/tests/test_throw.py,sha256=cowzx8900jpKon8-N4-UwsGH9ox5hfsqtDoVUNat84g,3734 +greenlet/tests/test_tracing.py,sha256=KjZh3t-4f9q1YG5JJ0sKxmwXUwDnpRHU1Y4x0Fi4N3E,7843 +greenlet/tests/test_version.py,sha256=O9DpAITsOFgiRcjd4odQ7ejmwx_N9Q1zQENVcbtFHIc,1339 +greenlet/tests/test_weakref.py,sha256=NWOaaJOMn83oKdXGoGzGAswb-QRHprlF2f0-4igjZMI,898 diff --git a/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/WHEEL b/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/WHEEL new file mode 100644 index 000000000..7d9ab249c --- /dev/null +++ b/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.38.4) +Root-Is-Purelib: false +Tag: cp311-cp311-win_amd64 + diff --git a/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/top_level.txt b/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/top_level.txt new file mode 100644 index 000000000..46725be4f --- /dev/null +++ b/.venv/Lib/site-packages/greenlet-2.0.2.dist-info/top_level.txt @@ -0,0 +1 @@ +greenlet diff --git a/.venv/Lib/site-packages/greenlet/__init__.py b/.venv/Lib/site-packages/greenlet/__init__.py new file mode 100644 index 000000000..ada1165d5 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/__init__.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +""" +The root of the greenlet package. +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +__all__ = [ + '__version__', + '_C_API', + + 'GreenletExit', + 'error', + + 'getcurrent', + 'greenlet', + + 'gettrace', + 'settrace', +] + +# pylint:disable=no-name-in-module + +### +# Metadata +### +__version__ = '2.0.2' +from ._greenlet import _C_API # pylint:disable=no-name-in-module + +### +# Exceptions +### +from ._greenlet import GreenletExit +from ._greenlet import error + +### +# greenlets +### +from ._greenlet import getcurrent +from ._greenlet import greenlet + +### +# tracing +### +try: + from ._greenlet import gettrace + from ._greenlet import settrace +except ImportError: + # Tracing wasn't supported. + # XXX: The option to disable it was removed in 1.0, + # so this branch should be dead code. + pass + +### +# Constants +# These constants aren't documented and aren't recommended. +# In 1.0, USE_GC and USE_TRACING are always true, and USE_CONTEXT_VARS +# is the same as ``sys.version_info[:2] >= 3.7`` +### +from ._greenlet import GREENLET_USE_CONTEXT_VARS # pylint:disable=unused-import +from ._greenlet import GREENLET_USE_GC # pylint:disable=unused-import +from ._greenlet import GREENLET_USE_TRACING # pylint:disable=unused-import + +# Controlling the use of the gc module. Provisional API for this greenlet +# implementation in 2.0. +from ._greenlet import CLOCKS_PER_SEC # pylint:disable=unused-import +from ._greenlet import enable_optional_cleanup # pylint:disable=unused-import +from ._greenlet import get_clocks_used_doing_optional_cleanup # pylint:disable=unused-import + +# Other APIS in the _greenlet module are for test support. diff --git a/.venv/Lib/site-packages/greenlet/__pycache__/__init__.cpython-311.pyc b/.venv/Lib/site-packages/greenlet/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3b127dbf6ad7dfd6ce928a5763f05e993c37b7ba GIT binary patch literal 1357 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

}j^~z=WWO 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 +#include +#include +#include + + +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" // PyMemberDef + +#include "greenlet_internal.hpp" +#include "greenlet_refs.hpp" +#include "greenlet_slp_switch.hpp" +#include "greenlet_thread_state.hpp" +#include "greenlet_thread_support.hpp" +#include "greenlet_greenlet.hpp" + +using greenlet::ThreadState; +using greenlet::Mutex; +using greenlet::LockGuard; +using greenlet::LockInitError; +using greenlet::PyErrOccurred; +using greenlet::Require; +using greenlet::PyFatalError; +using greenlet::ExceptionState; +using greenlet::StackState; +using greenlet::Greenlet; + + +// Helpers for reference counting. +// XXX: running the test cases for greenlet 1.1.2 under Python 3.10+pydebug +// with zope.testrunner's "report refcounts" option shows a growth of +// over 500 references when running 90 tests at a steady state (10 repeats) +// Running in verbose mode and adding objgraph to report gives us this +// info in a steady state: +// Ran 90 tests with 0 failures, 0 errors and 1 skipped in 2.120 seconds. +// Showing growth +// tuple 2811 +16 +// list 1733 +14 +// function 6304 +11 +// dict 3604 +9 +// cell 707 +9 +// greenlet 81 +8 +// method 103 +5 +// Genlet 40 +4 +// list_iterator 30 +3 +// getset_descriptor 916 +2 +// sum detail refcount=341678 sys refcount=379357 change=523 +// Leak details, changes in instances and refcounts by type/class: +// type/class insts refs +// ------------------------------------------------------- ----- ---- +// builtins.NoneType 0 2 +// builtins.cell 9 20 +// builtins.code 0 31 +// builtins.dict 18 91 +// builtins.frame 20 32 +// builtins.function 11 28 +// builtins.getset_descriptor 2 2 +// builtins.int 2 42 +// builtins.list 14 37 +// builtins.list_iterator 3 3 +// builtins.method 5 5 +// builtins.method_descriptor 0 9 +// builtins.str 11 76 +// builtins.traceback 1 2 +// builtins.tuple 20 42 +// builtins.type 2 28 +// builtins.weakref 2 2 +// greenlet.GreenletExit 1 1 +// greenlet.greenlet 8 26 +// greenlet.tests.test_contextvars.NoContextVarsTests 0 1 +// greenlet.tests.test_gc.object_with_finalizer 1 1 +// greenlet.tests.test_generator_nested.Genlet 4 26 +// greenlet.tests.test_greenlet.convoluted 1 2 +// ------------------------------------------------------- ----- ---- +// total 135 509 +// +// As of the commit that adds this comment, we're doing better than +// 1.1.2, but still not perfect: +// Ran 115 tests with 0 failures, 0 errors, 1 skipped in 8.623 seconds. +// tuple 21310 +23 +// dict 5428 +18 +// frame 183 +17 +// list 1760 +14 +// function 6359 +11 +// cell 698 +8 +// method 105 +5 +// int 2709 +4 +// TheGenlet 40 +4 +// list_iterator 30 +3 +// sum detail refcount=345051 sys refcount=383043 change=494 +// Leak details, changes in instances and refcounts by type/class: +// type/class insts refs +// ------------------------------------------------------- ----- ---- +// builtins.NoneType 0 12 +// builtins.bool 0 2 +// builtins.cell 8 16 +// builtins.code 0 28 +// builtins.dict 18 74 +// builtins.frame 17 28 +// builtins.function 11 28 +// builtins.getset_descriptor 2 2 +// builtins.int 4 44 +// builtins.list 14 39 +// builtins.list_iterator 3 3 +// builtins.method 5 5 +// builtins.method_descriptor 0 8 +// builtins.str -2 69 +// builtins.tuple 23 42 +// builtins.type 2 28 +// builtins.weakref 2 2 +// greenlet.greenlet 1 1 +// greenlet.main_greenlet 1 16 +// greenlet.tests.test_contextvars.NoContextVarsTests 0 1 +// greenlet.tests.test_gc.object_with_finalizer 1 1 +// greenlet.tests.test_generator_nested.TheGenlet 4 29 +// greenlet.tests.test_greenlet.convoluted 1 2 +// greenlet.tests.test_leaks.HasFinalizerTracksInstances 2 2 +// ------------------------------------------------------- ----- ---- +// total 117 482 + +using greenlet::refs::BorrowedObject; +using greenlet::refs::BorrowedGreenlet; +using greenlet::refs::BorrowedMainGreenlet; +using greenlet::refs::OwnedObject; +using greenlet::refs::PyErrFetchParam; +using greenlet::refs::PyArgParseParam; +using greenlet::refs::ImmortalString; +using greenlet::refs::ImmortalObject; +using greenlet::refs::CreatedModule; +using greenlet::refs::PyErrPieces; +using greenlet::refs::PyObjectPointer; +using greenlet::Greenlet; +using greenlet::UserGreenlet; +using greenlet::MainGreenlet; + + +// ******* Implementation of things from included files +template +greenlet::refs::_BorrowedGreenlet& greenlet::refs::_BorrowedGreenlet::operator=(const greenlet::refs::BorrowedObject& other) +{ + this->_set_raw_pointer(static_cast(other)); + return *this; +} + +template +inline greenlet::refs::_BorrowedGreenlet::operator Greenlet*() const G_NOEXCEPT +{ + if (!this->p) { + return nullptr; + } + return reinterpret_cast(this->p)->pimpl; +} + +template +greenlet::refs::_BorrowedGreenlet::_BorrowedGreenlet(const BorrowedObject& p) + : BorrowedReference(nullptr) +{ + + this->_set_raw_pointer(p.borrow()); +} + +template +inline greenlet::refs::_OwnedGreenlet::operator Greenlet*() const G_NOEXCEPT +{ + if (!this->p) { + return nullptr; + } + return reinterpret_cast(this->p)->pimpl; +} + + + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wmissing-field-initializers" +# pragma clang diagnostic ignored "-Wwritable-strings" +#elif defined(__GNUC__) +# pragma GCC diagnostic push +// warning: ISO C++ forbids converting a string constant to ‘char*’ +// (The python APIs aren't const correct and accept writable char*) +# pragma GCC diagnostic ignored "-Wwrite-strings" +#endif + + +/*********************************************************** + +A PyGreenlet is a range of C stack addresses that must be +saved and restored in such a way that the full range of the +stack contains valid data when we switch to it. + +Stack layout for a greenlet: + + | ^^^ | + | older data | + | | + stack_stop . |_______________| + . | | + . | greenlet data | + . | in stack | + . * |_______________| . . _____________ stack_copy + stack_saved + . | | | | + . | data | |greenlet data| + . | unrelated | | saved | + . | to | | in heap | + stack_start . | this | . . |_____________| stack_copy + | greenlet | + | | + | newer data | + | vvv | + + +Note that a greenlet's stack data is typically partly at its correct +place in the stack, and partly saved away in the heap, but always in +the above configuration: two blocks, the more recent one in the heap +and the older one still in the stack (either block may be empty). + +Greenlets are chained: each points to the previous greenlet, which is +the one that owns the data currently in the C stack above my +stack_stop. The currently running greenlet is the first element of +this chain. The main (initial) greenlet is the last one. Greenlets +whose stack is entirely in the heap can be skipped from the chain. + +The chain is not related to execution order, but only to the order +in which bits of C stack happen to belong to greenlets at a particular +point in time. + +The main greenlet doesn't have a stack_stop: it is responsible for the +complete rest of the C stack, and we don't know where it begins. We +use (char*) -1, the largest possible address. + +States: + stack_stop == NULL && stack_start == NULL: did not start yet + stack_stop != NULL && stack_start == NULL: already finished + stack_stop != NULL && stack_start != NULL: active + +The running greenlet's stack_start is undefined but not NULL. + + ***********************************************************/ + +/*** global state ***/ + +/* In the presence of multithreading, this is a bit tricky; see + greenlet_thread_state.hpp for details. +*/ + + +static inline OwnedObject +single_result(const OwnedObject& results) +{ + if (results + && PyTuple_Check(results.borrow()) + && PyTuple_GET_SIZE(results.borrow()) == 1) { + PyObject* result = PyTuple_GET_ITEM(results.borrow(), 0); + return OwnedObject::owning(result); + } + return results; +} + + + +class ImmortalEventName : public ImmortalString +{ +private: + G_NO_COPIES_OF_CLS(ImmortalEventName); +public: + ImmortalEventName(const char* const str) : ImmortalString(str) + {} +}; + +class ImmortalException : public ImmortalObject +{ +private: + G_NO_COPIES_OF_CLS(ImmortalException); +public: + ImmortalException(const char* const name, PyObject* base=nullptr) : + ImmortalObject(name + // Python 2.7 isn't const correct + ? Require(PyErr_NewException((char*)name, base, nullptr)) + : nullptr) + {} + + inline bool PyExceptionMatches() const + { + return PyErr_ExceptionMatches(this->p) > 0; + } + +}; + +// This encapsulates what were previously module global "constants" +// established at init time. +// This is a step towards Python3 style module state that allows +// reloading. +// We play some tricks with placement new to be able to allocate this +// object statically still, so that references to its members don't +// incur an extra pointer indirection. +class GreenletGlobals +{ +public: + const ImmortalEventName event_switch; + const ImmortalEventName event_throw; + const ImmortalException PyExc_GreenletError; + const ImmortalException PyExc_GreenletExit; + const ImmortalObject empty_tuple; + const ImmortalObject empty_dict; + const ImmortalString str_run; + Mutex* const thread_states_to_destroy_lock; + greenlet::cleanup_queue_t thread_states_to_destroy; + + GreenletGlobals(const int UNUSED(dummy)) : + event_switch(0), + event_throw(0), + PyExc_GreenletError(0), + PyExc_GreenletExit(0), + empty_tuple(0), + empty_dict(0), + str_run(0), + thread_states_to_destroy_lock(0) + {} + + GreenletGlobals() : + event_switch("switch"), + event_throw("throw"), + PyExc_GreenletError("greenlet.error"), + PyExc_GreenletExit("greenlet.GreenletExit", PyExc_BaseException), + empty_tuple(Require(PyTuple_New(0))), + empty_dict(Require(PyDict_New())), + str_run("run"), + thread_states_to_destroy_lock(new Mutex()) + {} + + ~GreenletGlobals() + { + // This object is (currently) effectively immortal, and not + // just because of those placement new tricks; if we try to + // deallocate the static object we allocated, and overwrote, + // we would be doing so at C++ teardown time, which is after + // the final Python GIL is released, and we can't use the API + // then. + // (The members will still be destructed, but they also don't + // do any deallocation.) + } + + void queue_to_destroy(ThreadState* ts) const + { + // we're currently accessed through a static const object, + // implicitly marking our members as const, so code can't just + // call push_back (or pop_back) without casting away the + // const. + // + // Do that for callers. + greenlet::cleanup_queue_t& q = const_cast(this->thread_states_to_destroy); + q.push_back(ts); + } + + ThreadState* take_next_to_destroy() const + { + greenlet::cleanup_queue_t& q = const_cast(this->thread_states_to_destroy); + ThreadState* result = q.back(); + q.pop_back(); + return result; + } +}; + +static const GreenletGlobals mod_globs(0); + +// Protected by the GIL. Incremented when we create a main greenlet, +// in a new thread, decremented when it is destroyed. +static Py_ssize_t total_main_greenlets; + +struct ThreadState_DestroyWithGIL +{ + ThreadState_DestroyWithGIL(ThreadState* state) + { + if (state && state->has_main_greenlet()) { + DestroyWithGIL(state); + } + } + + static int + DestroyWithGIL(ThreadState* state) + { + // Holding the GIL. + // Passed a non-shared pointer to the actual thread state. + // state -> main greenlet + assert(state->has_main_greenlet()); + PyGreenlet* main(state->borrow_main_greenlet()); + // When we need to do cross-thread operations, we check this. + // A NULL value means the thread died some time ago. + // We do this here, rather than in a Python dealloc function + // for the greenlet, in case there's still a reference out + // there. + static_cast(main->pimpl)->thread_state(nullptr); + + delete state; // Deleting this runs the destructor, DECREFs the main greenlet. + return 0; + } +}; + +#if (PY_VERSION_HEX >= 0x30800A0 && PY_VERSION_HEX < 0x3090000) && !(defined(_WIN32) || defined(WIN32)) +// XXX: From Python 3.8a3 [1] up until Python 3.9a6 [2][3], +// ``Py_AddPendingCall`` would try to produce a Python exception if +// the interpreter was in the beginning of shutting down when this +// function is called. However, ``Py_AddPendingCall`` doesn't require +// the GIL, and we are absolutely not holding it when we make that +// call. That means that trying to create the Python exception is +// using the C API in an undefined state; here the C API detects this +// and aborts the process with an error ("Fatal Python error: Python +// memory allocator called without holding the GIL": Add -> +// PyErr_SetString -> PyUnicode_New -> PyObject_Malloc). This arises +// (obviously) in multi-threaded programs and happens if one thread is +// exiting and cleaning up its thread-local data while the other +// thread is trying to shut down the interpreter. A crash on shutdown +// is still a crash and could result in data loss (e.g., daemon +// threads are still running, pending signal handlers may be present, +// buffers may not be flushed, there may be __del__ that need run, +// etc), so we have to work around it. +// +// Of course, we can (and do) check for whether the interpreter is +// shutting down before calling ``Py_AddPendingCall``, but that's a +// race condition since we don't hold the GIL, and so we may not +// actually get the right answer. Plus, ``Py_FinalizeEx`` actually +// calls ``_Py_FinishPendingCalls`` (which sets the pending->finishing +// flag, which is used to gate creating the exceptioen) *before* +// publishing any other data that would let us detect the shutdown +// (such as runtime->finalizing). So that point is moot. +// +// Our solution for those versions is to inline the same code, without +// the problematic bit that sets the exception. Unfortunately, all of +// the structure definitions are private/opaque, *and* we can't +// actually count on being able to include their definitions from +// ``internal/pycore_*``, because on some platforms those header files +// are incomplete (i.e., on macOS with macports 3.8, the includes are +// fine, but on Ubuntu jammy with 3.8 from ppa:deadsnakes or GitHub +// Actions 3.8 (I think it's Ubuntu 18.04), they con't be used; at +// least, I couldn't get them to work). So we need to define the +// structures and _PyRuntime data member ourself. Yet more +// unfortunately, _PyRuntime won't link on Windows, so we can only do +// this on other platforms. +// +// [1] https://github.com/python/cpython/commit/842a2f07f2f08a935ef470bfdaeef40f87490cfc +// [2] https://github.com/python/cpython/commit/cfc3c2f8b34d3864717ab584c5b6c260014ba55a +// [3] https://github.com/python/cpython/issues/81308 +# define GREENLET_BROKEN_PY_ADD_PENDING 1 + +// When defining these structures, the important thing is to get +// binary compatibility, i.e., structure layout. For that, we only +// need to define fields up to the ones we use; after that they're +// irrelevant UNLESS the structure is included in another structure +// *before* the structure we're interested in --- in that case, it +// must be complete. Ellipsis indicate elided trailing members. +// Pointer types are changed to void* to keep from having to define +// more structures. + +// From "internal/pycore_atomic.h" + +// There are several different definitions of this, including the +// plain ``int`` version, a ``volatile int`` and an ``_Atomic int`` +// I don't think any of those change the size/layout. +typedef struct _Py_atomic_int { + volatile int _value; +} _Py_atomic_int; + +// This needs too much infrastructure, so we just do a regular store. +#define _Py_atomic_store_relaxed(ATOMIC_VAL, NEW_VAL) \ + (ATOMIC_VAL)->_value = NEW_VAL + + + +// From "internal/pycore_pymem.h" +#define NUM_GENERATIONS 3 + + +struct gc_generation { + PyGC_Head head; // We already have this defined. + int threshold; + int count; +}; +struct gc_generation_stats { + Py_ssize_t collections; + Py_ssize_t collected; + Py_ssize_t uncollectable; +}; + +struct _gc_runtime_state { + void *trash_delete_later; + int trash_delete_nesting; + int enabled; + int debug; + struct gc_generation generations[NUM_GENERATIONS]; + void *generation0; + struct gc_generation permanent_generation; + struct gc_generation_stats generation_stats[NUM_GENERATIONS]; + int collecting; + void *garbage; + void *callbacks; + Py_ssize_t long_lived_total; + Py_ssize_t long_lived_pending; +}; + +// From "internal/pycore_pystate.h" +struct _pending_calls { + int finishing; + PyThread_type_lock lock; + _Py_atomic_int calls_to_do; + int async_exc; +#define NPENDINGCALLS 32 + struct { + int (*func)(void *); + void *arg; + } calls[NPENDINGCALLS]; + int first; + int last; +}; + +struct _ceval_runtime_state { + int recursion_limit; + int tracing_possible; + _Py_atomic_int eval_breaker; + _Py_atomic_int gil_drop_request; + struct _pending_calls pending; + // ... +}; + +typedef struct pyruntimestate { + int preinitializing; + int preinitialized; + int core_initialized; + int initialized; + void *finalizing; + + struct pyinterpreters { + PyThread_type_lock mutex; + void *head; + void *main; + int64_t next_id; + } interpreters; + // XXX Remove this field once we have a tp_* slot. + struct _xidregistry { + PyThread_type_lock mutex; + void *head; + } xidregistry; + + unsigned long main_thread; + +#define NEXITFUNCS 32 + void (*exitfuncs[NEXITFUNCS])(void); + int nexitfuncs; + + struct _gc_runtime_state gc; + struct _ceval_runtime_state ceval; + // ... +} _PyRuntimeState; + +#define SIGNAL_PENDING_CALLS(ceval) \ + do { \ + _Py_atomic_store_relaxed(&(ceval)->pending.calls_to_do, 1); \ + _Py_atomic_store_relaxed(&(ceval)->eval_breaker, 1); \ + } while (0) + +extern _PyRuntimeState _PyRuntime; + +#else +# define GREENLET_BROKEN_PY_ADD_PENDING 0 +#endif + + +struct ThreadState_DestroyNoGIL +{ +#if GREENLET_BROKEN_PY_ADD_PENDING + static int _push_pending_call(struct _pending_calls *pending, + int (*func)(void *), void *arg) + { + int i = pending->last; + int j = (i + 1) % NPENDINGCALLS; + if (j == pending->first) { + return -1; /* Queue full */ + } + pending->calls[i].func = func; + pending->calls[i].arg = arg; + pending->last = j; + return 0; + } + + static int AddPendingCall(int (*func)(void *), void *arg) + { + _PyRuntimeState *runtime = &_PyRuntime; + if (!runtime) { + // obviously impossible + return 0; + } + struct _pending_calls *pending = &runtime->ceval.pending; + if (!pending->lock) { + return 0; + } + int result = 0; + PyThread_acquire_lock(pending->lock, WAIT_LOCK); + if (!pending->finishing) { + result = _push_pending_call(pending, func, arg); + } + PyThread_release_lock(pending->lock); + SIGNAL_PENDING_CALLS(&runtime->ceval); + return result; + } +#else + // Python < 3.8 or >= 3.9 + static int AddPendingCall(int (*func)(void*), void* arg) + { + return Py_AddPendingCall(func, arg); + } +#endif + + ThreadState_DestroyNoGIL(ThreadState* state) + { + // We are *NOT* holding the GIL. Our thread is in the middle + // of its death throes and the Python thread state is already + // gone so we can't use most Python APIs. One that is safe is + // ``Py_AddPendingCall``, unless the interpreter itself has + // been torn down. There is a limited number of calls that can + // be queued: 32 (NPENDINGCALLS) in CPython 3.10, so we + // coalesce these calls using our own queue. + if (state && state->has_main_greenlet()) { + // mark the thread as dead ASAP. + // this is racy! If we try to throw or switch to a + // greenlet from this thread from some other thread before + // we clear the state pointer, it won't realize the state + // is dead which can crash the process. + PyGreenlet* p = state->borrow_main_greenlet(); + assert(p->pimpl->thread_state() == state || p->pimpl->thread_state() == nullptr); + static_cast(p->pimpl)->thread_state(nullptr); + } + + // NOTE: Because we're not holding the GIL here, some other + // Python thread could run and call ``os.fork()``, which would + // be bad if that happenend while we are holding the cleanup + // lock (it wouldn't function in the child process). + // Make a best effort to try to keep the duration we hold the + // lock short. + // TODO: On platforms that support it, use ``pthread_atfork`` to + // drop this lock. + LockGuard cleanup_lock(*mod_globs.thread_states_to_destroy_lock); + + if (state && state->has_main_greenlet()) { + // Because we don't have the GIL, this is a race condition. + if (!PyInterpreterState_Head()) { + // We have to leak the thread state, if the + // interpreter has shut down when we're getting + // deallocated, we can't run the cleanup code that + // deleting it would imply. + return; + } + + mod_globs.queue_to_destroy(state); + if (mod_globs.thread_states_to_destroy.size() == 1) { + // We added the first item to the queue. We need to schedule + // the cleanup. + int result = ThreadState_DestroyNoGIL::AddPendingCall( + ThreadState_DestroyNoGIL::DestroyQueueWithGIL, + NULL); + if (result < 0) { + // Hmm, what can we do here? + fprintf(stderr, + "greenlet: WARNING: failed in call to Py_AddPendingCall; " + "expect a memory leak.\n"); + } + } + } + } + + static int + DestroyQueueWithGIL(void* UNUSED(arg)) + { + // We're holding the GIL here, so no Python code should be able to + // run to call ``os.fork()``. + while (1) { + ThreadState* to_destroy; + { + LockGuard cleanup_lock(*mod_globs.thread_states_to_destroy_lock); + if (mod_globs.thread_states_to_destroy.empty()) { + break; + } + to_destroy = mod_globs.take_next_to_destroy(); + } + // Drop the lock while we do the actual deletion. + ThreadState_DestroyWithGIL::DestroyWithGIL(to_destroy); + } + return 0; + } + +}; + +// The intent when GET_THREAD_STATE() is used multiple times in a function is to +// take a reference to it in a local variable, to avoid the +// thread-local indirection. On some platforms (macOS), +// accessing a thread-local involves a function call (plus an initial +// function call in each function that uses a thread local); in +// contrast, static volatile variables are at some pre-computed offset. + +#if G_USE_STANDARD_THREADING == 1 +typedef greenlet::ThreadStateCreator ThreadStateCreator; +static G_THREAD_LOCAL_VAR ThreadStateCreator g_thread_state_global; +#define GET_THREAD_STATE() g_thread_state_global +#else +// if we're not using standard threading, we're using +// the Python thread-local dictionary to perform our cleanup, +// which means we're deallocated when holding the GIL. The +// thread state is valid enough still for us to destroy +// stuff. +typedef greenlet::ThreadStateCreator ThreadStateCreator; +#define G_THREAD_STATE_DICT_CLEANUP_TYPE +#include "greenlet_thread_state_dict_cleanup.hpp" +typedef greenlet::refs::OwnedReference OwnedGreenletCleanup; +// RECALL: legacy thread-local objects (__thread on GCC, __declspec(thread) on +// MSVC) can't have constructors or destructors, they have to be +// constant. So we indirect through a pointer and a function. +static G_THREAD_LOCAL_VAR ThreadStateCreator* _g_thread_state_global_ptr = nullptr; +static ThreadStateCreator& GET_THREAD_STATE() +{ + if (!_g_thread_state_global_ptr) { + // NOTE: If any of this fails, we'll probably go on to hard + // crash the process, because we're returning a reference to a + // null pointer. we've called Py_FatalError(), but have no way + // to communicate that to the caller. Since these should + // essentially never fail unless the entire process is borked, + // a hard crash with a decent C++ backtrace from the exception + // is much more useful. + _g_thread_state_global_ptr = new ThreadStateCreator(); + if (!_g_thread_state_global_ptr) { + throw PyFatalError("greenlet: Failed to create greenlet thread state."); + } + + OwnedGreenletCleanup cleanup(OwnedGreenletCleanup::consuming(PyType_GenericAlloc(&PyGreenletCleanup_Type, 0))); + if (!cleanup) { + throw PyFatalError("greenlet: Failed to create greenlet thread state cleanup."); + } + + cleanup->thread_state_creator = _g_thread_state_global_ptr; + assert(PyObject_GC_IsTracked(cleanup.borrow_o())); + + PyObject* ts_dict_w = PyThreadState_GetDict(); + if (!ts_dict_w) { + throw PyFatalError("greenlet: Failed to get Python thread state."); + } + if (PyDict_SetItemString(ts_dict_w, "__greenlet_cleanup", cleanup.borrow_o()) < 0) { + throw PyFatalError("greenlet: Failed to save cleanup key in Python thread state."); + } + } + return *_g_thread_state_global_ptr; +} +#endif + + +Greenlet::Greenlet(PyGreenlet* p) +{ + p ->pimpl = this; +} + +Greenlet::Greenlet(PyGreenlet* p, const StackState& initial_stack) + : stack_state(initial_stack) +{ + // can't use a delegating constructor because of + // MSVC for Python 2.7 + p->pimpl = this; +} + +UserGreenlet::UserGreenlet(PyGreenlet* p,BorrowedGreenlet the_parent) + : Greenlet(p), _parent(the_parent) +{ + this->_self = p; +} + + +MainGreenlet::MainGreenlet(PyGreenlet* p, ThreadState* state) + : Greenlet(p, StackState::make_main()), + _self(p), + _thread_state(state) +{ + total_main_greenlets++; +} + +ThreadState* +MainGreenlet::thread_state() const G_NOEXCEPT +{ + return this->_thread_state; +} + +void +MainGreenlet::thread_state(ThreadState* t) G_NOEXCEPT +{ + assert(!t); + this->_thread_state = t; +} + +BorrowedGreenlet +UserGreenlet::self() const G_NOEXCEPT +{ + return this->_self; +} + +BorrowedGreenlet +MainGreenlet::self() const G_NOEXCEPT +{ + return BorrowedGreenlet(this->_self.borrow()); +} + +const BorrowedMainGreenlet +UserGreenlet::main_greenlet() const +{ + return this->_main_greenlet; +} + +const BorrowedMainGreenlet +MainGreenlet::main_greenlet() const +{ + return this->_self; +} + +static PyGreenlet* +green_create_main(ThreadState* state) +{ + PyGreenlet* gmain; + + /* create the main greenlet for this thread */ + gmain = (PyGreenlet*)PyType_GenericAlloc(&PyGreenlet_Type, 0); + if (gmain == NULL) { + Py_FatalError("green_create_main failed to alloc"); + return NULL; + } + new MainGreenlet(gmain, state); + + assert(Py_REFCNT(gmain) == 1); + return gmain; +} + + +BorrowedMainGreenlet +UserGreenlet::find_main_greenlet_in_lineage() const +{ + if (this->started()) { + assert(this->_main_greenlet); + return BorrowedMainGreenlet(this->_main_greenlet); + } + + if (!this->_parent) { + /* garbage collected greenlet in chain */ + // XXX: WHAT? + return BorrowedMainGreenlet(nullptr); + } + + return this->_parent->find_main_greenlet_in_lineage(); +} + + +BorrowedMainGreenlet +MainGreenlet::find_main_greenlet_in_lineage() const +{ + return BorrowedMainGreenlet(this->_self); +} + +/***********************************************************/ + +/* Some functions must not be inlined: + * slp_restore_state, when inlined into slp_switch might cause + it to restore stack over its own local variables + * slp_save_state, when inlined would add its own local + variables to the saved stack, wasting space + * slp_switch, cannot be inlined for obvious reasons + * g_initialstub, when inlined would receive a pointer into its + own stack frame, leading to incomplete stack save/restore + +g_initialstub is a member function and declared virtual so that the +compiler always calls it through a vtable. + +slp_save_state and slp_restore_state are also member functions. They +are called from trampoline functions that themselves are declared as +not eligible for inlining. +*/ + + + +/* add forward declarations */ + + +static void +g_calltrace(const OwnedObject& tracefunc, + const ImmortalEventName& event, + const BorrowedGreenlet& origin, + const BorrowedGreenlet& target); + +static OwnedObject +g_handle_exit(const OwnedObject& greenlet_result); + + + + + +/** + * CAUTION: May invoke arbitrary Python code. + * + * Figure out what the result of ``greenlet.switch(arg, kwargs)`` + * should be and transfers ownership of it to the left-hand-side. + * + * If switch() was just passed an arg tuple, then we'll just return that. + * If only keyword arguments were passed, then we'll pass the keyword + * argument dict. Otherwise, we'll create a tuple of (args, kwargs) and + * return both. + */ +OwnedObject& operator<<=(OwnedObject& lhs, greenlet::SwitchingArgs& rhs) G_NOEXCEPT +{ + // Because this may invoke arbitrary Python code, which could + // result in switching back to us, we need to get the + // arguments locally on the stack. + assert(rhs); + OwnedObject args = rhs.args(); + OwnedObject kwargs = rhs.kwargs(); + rhs.CLEAR(); + // We shouldn't be called twice for the same switch. + assert(args || kwargs); + assert(!rhs); + + if (!kwargs) { + lhs = args; + } + else if (!PyDict_Size(kwargs.borrow())) { + lhs = args; + } + else if (!PySequence_Length(args.borrow())) { + lhs = kwargs; + } + else { + lhs = OwnedObject::consuming(PyTuple_Pack(2, args.borrow(), kwargs.borrow())); + } + return lhs; +} + + + +void Greenlet::release_args() +{ + this->switch_args.CLEAR(); +} + + +void* UserGreenlet::operator new(size_t UNUSED(count)) +{ + return allocator.allocate(1); +} + + +void UserGreenlet::operator delete(void* ptr) +{ + return allocator.deallocate(static_cast(ptr), + 1); +} + +void* MainGreenlet::operator new(size_t UNUSED(count)) +{ + return allocator.allocate(1); +} + + +void MainGreenlet::operator delete(void* ptr) +{ + return allocator.deallocate(static_cast(ptr), + 1); +} + + +OwnedObject +Greenlet::throw_GreenletExit_during_dealloc(const ThreadState& UNUSED(current_thread_state)) +{ + // If we're killed because we lost all references in the + // middle of a switch, that's ok. Don't reset the args/kwargs, + // we still want to pass them to the parent. + PyErr_SetString(mod_globs.PyExc_GreenletExit, + "Killing the greenlet because all references have vanished."); + // To get here it had to have run before + return this->g_switch(); +} + +OwnedObject +UserGreenlet::throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state) +{ + /* The dying greenlet cannot be a parent of ts_current + because the 'parent' field chain would hold a + reference */ + UserGreenlet::ParentIsCurrentGuard with_current_parent(this, current_thread_state); + + // We don't care about the return value, only whether an + // exception happened. Whether or not an exception happens, + // we need to restore the parent in case the greenlet gets + // resurrected. + return Greenlet::throw_GreenletExit_during_dealloc(current_thread_state); +} + +ThreadState* +UserGreenlet::thread_state() const G_NOEXCEPT +{ + // TODO: maybe make this throw, if the thread state isn't there? + // if (!this->main_greenlet) { + // throw std::runtime_error("No thread state"); // TODO: Better exception + // } + if (!this->_main_greenlet) { + return nullptr; + } + return this->_main_greenlet->thread_state(); +} + + + +bool +UserGreenlet::was_running_in_dead_thread() const G_NOEXCEPT +{ + return this->_main_greenlet && !this->thread_state(); +} + +bool +MainGreenlet::was_running_in_dead_thread() const G_NOEXCEPT +{ + return !this->_thread_state; +} + +inline void +Greenlet::slp_restore_state() G_NOEXCEPT +{ +#ifdef SLP_BEFORE_RESTORE_STATE + SLP_BEFORE_RESTORE_STATE(); +#endif + this->stack_state.copy_heap_to_stack( + this->thread_state()->borrow_current()->stack_state); +} + + +inline int +Greenlet::slp_save_state(char *const stackref) G_NOEXCEPT +{ + // XXX: This used to happen in the middle, before saving, but + // after finding the next owner. Does that matter? This is + // only defined for Sparc/GCC where it flushes register + // windows to the stack (I think) +#ifdef SLP_BEFORE_SAVE_STATE + SLP_BEFORE_SAVE_STATE(); +#endif + return this->stack_state.copy_stack_to_heap(stackref, + this->thread_state()->borrow_current()->stack_state); +} + + +OwnedObject +UserGreenlet::g_switch() +{ + try { + this->check_switch_allowed(); + } + catch(const PyErrOccurred&) { + this->release_args(); + throw; + } + + // Switching greenlets used to attempt to clean out ones that need + // deleted *if* we detected a thread switch. Should it still do + // that? + // An issue is that if we delete a greenlet from another thread, + // it gets queued to this thread, and ``kill_greenlet()`` switches + // back into the greenlet + + /* find the real target by ignoring dead greenlets, + and if necessary starting a greenlet. */ + switchstack_result_t err; + Greenlet* target = this; + // TODO: probably cleaner to handle the case where we do + // switch to ourself separately from the other cases. + // This can probably even further be simplified if we keep + // track of the switching_state we're going for and just call + // into g_switch() if it's not ourself. The main problem with that + // is that we would be using more stack space. + bool target_was_me = true; + while (target) { + + if (target->active()) { + if (!target_was_me) { + target->args() <<= this->switch_args; + assert(!this->switch_args); + } + err = target->g_switchstack(); + break; + } + if (!target->started()) { + // We never encounter a main greenlet that's not started. + assert(!target->main()); + UserGreenlet* real_target = static_cast(target); + assert(real_target); + void* dummymarker; + + if (!target_was_me) { + target->args() <<= this->switch_args; + assert(!this->switch_args); + } + + try { + // This can only throw back to us while we're + // still in this greenlet. Once the new greenlet + // is bootstrapped, it has its own exception state. + err = real_target->g_initialstub(&dummymarker); + } + catch (const PyErrOccurred&) { + this->release_args(); + throw; + } + catch (const GreenletStartedWhileInPython&) { + // The greenlet was started sometime before this + // greenlet actually switched to it, i.e., + // "concurrent" calls to switch() or throw(). + // We need to retry the switch. + // Note that the current greenlet has been reset + // to this one (or we wouldn't be running!) + continue; + } + break; + } + + target = target->parent(); + target_was_me = false; + } + // The this pointer and all other stack or register based + // variables are invalid now, at least where things succeed + // above. + // But this one, probably not so much? It's not clear if it's + // safe to throw an exception at this point. + + if (err.status < 0) { + // XXX: This code path is untested. + assert(PyErr_Occurred()); + assert(!err.the_state_that_switched); + assert(!err.origin_greenlet); + return OwnedObject(); + } + + return err.the_state_that_switched->g_switch_finish(err); +} + +OwnedObject +MainGreenlet::g_switch() +{ + try { + this->check_switch_allowed(); + } + catch(const PyErrOccurred&) { + this->release_args(); + throw; + } + + switchstack_result_t err = this->g_switchstack(); + if (err.status < 0) { + // XXX: This code path is untested. + assert(PyErr_Occurred()); + assert(!err.the_state_that_switched); + assert(!err.origin_greenlet); + return OwnedObject(); + } + + return err.the_state_that_switched->g_switch_finish(err); +} + + +OwnedGreenlet +Greenlet::g_switchstack_success() G_NOEXCEPT +{ + PyThreadState* tstate = PyThreadState_GET(); + // restore the saved state + this->python_state >> tstate; + this->exception_state >> tstate; + + // The thread state hasn't been changed yet. + ThreadState* thread_state = this->thread_state(); + OwnedGreenlet result(thread_state->get_current()); + thread_state->set_current(this->self()); + //assert(thread_state->borrow_current().borrow() == this->_self); + return result; +} + + +Greenlet::switchstack_result_t +UserGreenlet::g_initialstub(void* mark) +{ + OwnedObject run; + + // We need to grab a reference to the current switch arguments + // in case we're entered concurrently during the call to + // GetAttr() and have to try again. + // We'll restore them when we return in that case. + // Scope them tightly to avoid ref leaks. + { + SwitchingArgs args(this->switch_args); + + /* save exception in case getattr clears it */ + PyErrPieces saved; + + /* + self.run is the object to call in the new greenlet. + This could run arbitrary python code and switch greenlets! + */ + run = this->_self.PyRequireAttr(mod_globs.str_run); + + /* restore saved exception */ + saved.PyErrRestore(); + + + /* recheck that it's safe to switch in case greenlet reparented anywhere above */ + this->check_switch_allowed(); + + /* by the time we got here another start could happen elsewhere, + * that means it should now be a regular switch. + * This can happen if the Python code is a subclass that implements + * __getattribute__ or __getattr__, or makes ``run`` a descriptor; + * all of those can run arbitrary code that switches back into + * this greenlet. + */ + if (this->stack_state.started()) { + // the successful switch cleared these out, we need to + // restore our version. + assert(!this->switch_args); + this->switch_args <<= args; + + throw GreenletStartedWhileInPython(); + } + } + + // Sweet, if we got here, we have the go-ahead and will switch + // greenlets. + // Nothing we do from here on out should allow for a thread or + // greenlet switch: No arbitrary calls to Python, including + // decref'ing + +#if GREENLET_USE_CFRAME + /* OK, we need it, we're about to switch greenlets, save the state. */ + /* + See green_new(). This is a stack-allocated variable used + while *self* is in PyObject_Call(). + We want to defer copying the state info until we're sure + we need it and are in a stable place to do so. + */ + _PyCFrame trace_info; + + this->python_state.set_new_cframe(trace_info); +#endif + /* start the greenlet */ + ThreadState& thread_state = GET_THREAD_STATE().state(); + this->stack_state = StackState(mark, + thread_state.borrow_current()->stack_state); + this->python_state.set_initial_state(PyThreadState_GET()); + this->exception_state.clear(); + this->_main_greenlet = thread_state.get_main_greenlet(); + + /* perform the initial switch */ + switchstack_result_t err = this->g_switchstack(); + /* returns twice! + The 1st time with ``err == 1``: we are in the new greenlet. + This one owns a greenlet that used to be current. + The 2nd time with ``err <= 0``: back in the caller's + greenlet; this happens if the child finishes or switches + explicitly to us. Either way, the ``err`` variable is + created twice at the same memory location, but possibly + having different ``origin`` values. Note that it's not + constructed for the second time until the switch actually happens. + */ + if (err.status == 1) { + // This never returns! Calling inner_bootstrap steals + // the contents of our run object within this stack frame, so + // it is not valid to do anything with it. + this->inner_bootstrap(err.origin_greenlet, run); + Py_FatalError("greenlet: inner_bootstrap returned\n"); + } + // The child will take care of decrefing this. + run.relinquish_ownership(); + + // In contrast, notice that we're keeping the origin greenlet + // around as an owned reference; we need it to call the trace + // function for the switch back into the parent. It was only + // captured at the time the switch actually happened, though, + // so we haven't been keeping an extra reference around this + // whole time. + + /* back in the parent */ + if (err.status < 0) { + /* start failed badly, restore greenlet state */ + // XXX: This code path is not tested. + this->stack_state = StackState(); + this->_main_greenlet.CLEAR(); + fprintf(stderr, "greenlet: g_initialstub: starting child failed.\n"); + } + return err; +} + + +void +UserGreenlet::inner_bootstrap(OwnedGreenlet& origin_greenlet, OwnedObject& _run) G_NOEXCEPT_WIN32 +{ + // The arguments here would be another great place for move. + // As it is, we take them as a reference so that when we clear + // them we clear what's on the stack above us. Do that NOW, and + // without using a C++ RAII object, + // so there's no way that exiting the parent frame can clear it, + // or we clear it unexpectedly. This arises in the context of the + // interpreter shutting down. See https://github.com/python-greenlet/greenlet/issues/325 + PyObject* run = _run.relinquish_ownership(); + + /* in the new greenlet */ + assert(this->thread_state()->borrow_current() == this->_self); + // C++ exceptions cannot propagate to the parent greenlet from + // here. (TODO: Do we need a catch(...) clause, perhaps on the + // function itself? ALl we could do is terminate the program.) + // NOTE: On 32-bit Windows, the call chain is extremely + // important here in ways that are subtle, having to do with + // the depth of the SEH list. The call to restore it MUST NOT + // add a new SEH handler to the list, or we'll restore it to + // the wrong thing. + this->thread_state()->restore_exception_state(); + /* stack variables from above are no good and also will not unwind! */ + // EXCEPT: That can't be true, we access run, among others, here. + + this->stack_state.set_active(); /* running */ + + // XXX: We could clear this much earlier, right? + // Or would that introduce the possibility of running Python + // code when we don't want to? + this->_run_callable.CLEAR(); + + + // We're about to possibly run Python code again, which + // could switch back to us, so we need to grab the + // arguments locally. + SwitchingArgs args; + args <<= this->switch_args; + assert(!this->switch_args); + + // The first switch we need to manually call the trace + // function here instead of in g_switch_finish, because we + // never return there. + + if (OwnedObject tracefunc = this->thread_state()->get_tracefunc()) { + try { + g_calltrace(tracefunc, + args ? mod_globs.event_switch : mod_globs.event_throw, + origin_greenlet, + this->_self); + } + catch (const PyErrOccurred&) { + /* Turn trace errors into switch throws */ + args.CLEAR(); + } + } + + // We no longer need the origin, it was only here for + // tracing. + // We may never actually exit this stack frame so we need + // to explicitly clear it. + // This could run Python code and switch. + origin_greenlet.CLEAR(); + + OwnedObject result; + if (!args) { + /* pending exception */ + result = NULL; + } + else { + /* call g.run(*args, **kwargs) */ + // This could result in further switches + try { + //result = run.PyCall(args.args(), args.kwargs()); + result = OwnedObject::consuming(PyObject_Call(run, args.args().borrow(), args.kwargs().borrow())); + } + catch(...) { + // Unhandled C++ exception! + + // If we declare ourselves as noexcept, if we don't catch + // this here, most platforms will just abort() the + // process. But on 64-bit Windows with older versions of + // the C runtime, this can actually corrupt memory and + // just return. We see this when compiling with the + // Windows 7.0 SDK targeting Windows Server 2008, but not + // when using the Appveyor Visual Studio 2019 image. So + // this currently only affects Python 2.7 on Windows 64. + // That is, the tests pass and the runtime aborts + // everywhere else. + // + // However, if we catch it and try to continue with a + // Python error, then all Windows 64 bit platforms corrupt + // memory. So all we can do is manually abort, hopefully + // with a good error message. (Note that the above was + // tested WITHOUT the `/EHr` switch being used at compile + // time, so MSVC may have "optimized" out important + // checking. Using that switch, we may be in a better + // place in terms of memory corruption.) But sometimes it + // can't be caught here at all, which is confusing but not + // terribly surprising; so again, the G_NOEXCEPT_WIN32 + // plus "/EHr". + // + // Hopefully the basic C stdlib is still functional enough + // for us to at least print an error. + // + // It gets more complicated than that, though, on some + // platforms, specifically at least Linux/gcc/libstdc++. They use + // an exception to unwind the stack when a background + // thread exits. (See comments about G_NOEXCEPT.) So this + // may not actually represent anything untoward. On those + // platforms we allow throws of this to propagate, or + // attempt to anyway. +# if defined(WIN32) || defined(_WIN32) + Py_FatalError( + "greenlet: Unhandled C++ exception from a greenlet run function. " + "Because memory is likely corrupted, terminating process."); + std::abort(); +#else + throw; +#endif + } + } + args.CLEAR(); + Py_CLEAR(run); + + if (!result + && mod_globs.PyExc_GreenletExit.PyExceptionMatches() + && (this->switch_args)) { + // This can happen, for example, if our only reference + // goes away after we switch back to the parent. + // See test_dealloc_switch_args_not_lost + PyErrPieces clear_error; + result <<= this->switch_args; + result = single_result(result); + } + this->release_args(); + this->python_state.did_finish(PyThreadState_GET()); + + result = g_handle_exit(result); + assert(this->thread_state()->borrow_current() == this->_self); + + /* jump back to parent */ + this->stack_state.set_inactive(); /* dead */ + + + // TODO: Can we decref some things here? Release our main greenlet + // and maybe parent? + for (Greenlet* parent = this->_parent; + parent; + parent = parent->parent()) { + // We need to somewhere consume a reference to + // the result; in most cases we'll never have control + // back in this stack frame again. Calling + // green_switch actually adds another reference! + // This would probably be clearer with a specific API + // to hand results to the parent. + parent->args() <<= result; + assert(!result); + // The parent greenlet now owns the result; in the + // typical case we'll never get back here to assign to + // result and thus release the reference. + try { + result = parent->g_switch(); + } + catch (const PyErrOccurred&) { + // Ignore. + } + + /* Return here means switch to parent failed, + * in which case we throw *current* exception + * to the next parent in chain. + */ + assert(!result); + } + /* We ran out of parents, cannot continue */ + PyErr_WriteUnraisable(this->self().borrow_o()); + Py_FatalError("greenlet: ran out of parent greenlets while propagating exception; " + "cannot continue"); + std::abort(); +} + + +Greenlet::switchstack_result_t +Greenlet::g_switchstack(void) +{ + { /* save state */ + if (this->thread_state()->is_current(this->self())) { + // Hmm, nothing to do. + // TODO: Does this bypass trace events that are + // important? + return switchstack_result_t(0, + this, this->thread_state()->borrow_current()); + } + BorrowedGreenlet current = this->thread_state()->borrow_current(); + PyThreadState* tstate = PyThreadState_GET(); + current->python_state << tstate; + current->exception_state << tstate; + this->python_state.will_switch_from(tstate); + switching_thread_state = this; + } + // If this is the first switch into a greenlet, this will + // return twice, once with 1 in the new greenlet, once with 0 + // in the origin. + int err = slp_switch(); + + if (err < 0) { /* error */ + // XXX: This code path is not tested. + BorrowedGreenlet current(GET_THREAD_STATE().state().borrow_current()); + //current->top_frame = NULL; // This probably leaks? + current->exception_state.clear(); + + switching_thread_state = nullptr; + //GET_THREAD_STATE().state().wref_target(NULL); + this->release_args(); + // It's important to make sure not to actually return an + // owned greenlet here, no telling how long before it + // could be cleaned up. + // TODO: Can this be a throw? How stable is the stack in + // an error case like this? + return switchstack_result_t(err); + } + + // No stack-based variables are valid anymore. + + // But the global is volatile so we can reload it without the + // compiler caching it from earlier. + Greenlet* after_switch = switching_thread_state; + OwnedGreenlet origin = after_switch->g_switchstack_success(); + switching_thread_state = nullptr; + return switchstack_result_t(err, after_switch, origin); +} + + +inline void +Greenlet::check_switch_allowed() const +{ + // TODO: Make this take a parameter of the current greenlet, + // or current main greenlet, to make the check for + // cross-thread switching cheaper. Surely somewhere up the + // call stack we've already accessed the thread local variable. + + // We expect to always have a main greenlet now; accessing the thread state + // created it. However, if we get here and cleanup has already + // begun because we're a greenlet that was running in a + // (now dead) thread, these invariants will not hold true. In + // fact, accessing `this->thread_state` may not even be possible. + + // If the thread this greenlet was running in is dead, + // we'll still have a reference to a main greenlet, but the + // thread state pointer we have is bogus. + // TODO: Give the objects an API to determine if they belong + // to a dead thread. + + const BorrowedMainGreenlet main_greenlet = this->find_main_greenlet_in_lineage(); + + if (!main_greenlet) { + throw PyErrOccurred(mod_globs.PyExc_GreenletError, + "cannot switch to a garbage collected greenlet"); + } + + if (!main_greenlet->thread_state()) { + throw PyErrOccurred(mod_globs.PyExc_GreenletError, + "cannot switch to a different thread (which happens to have exited)"); + } + + // The main greenlet we found was from the .parent lineage. + // That may or may not have any relationship to the main + // greenlet of the running thread. We can't actually access + // our this->thread_state members to try to check that, + // because it could be in the process of getting destroyed, + // but setting the main_greenlet->thread_state member to NULL + // may not be visible yet. So we need to check against the + // current thread state (once the cheaper checks are out of + // the way) + const BorrowedMainGreenlet current_main_greenlet = GET_THREAD_STATE().state().borrow_main_greenlet(); + if ( + // lineage main greenlet is not this thread's greenlet + current_main_greenlet != main_greenlet + || ( + // atteched to some thread + this->main_greenlet() + // XXX: Same condition as above. Was this supposed to be + // this->main_greenlet()? + && current_main_greenlet != main_greenlet) + // switching into a known dead thread (XXX: which, if we get here, + // is bad, because we just accessed the thread state, which is + // gone!) + || (!current_main_greenlet->thread_state())) { + throw PyErrOccurred(mod_globs.PyExc_GreenletError, + "cannot switch to a different thread"); + } +} + + +OwnedObject +Greenlet::g_switch_finish(const switchstack_result_t& err) +{ + + ThreadState& state = *this->thread_state(); + try { + // Our only caller handles the bad error case + assert(err.status >= 0); + assert(state.borrow_current() == this->self()); + + if (OwnedObject tracefunc = state.get_tracefunc()) { + g_calltrace(tracefunc, + this->args() ? mod_globs.event_switch : mod_globs.event_throw, + err.origin_greenlet, + this->self()); + } + // The above could have invoked arbitrary Python code, but + // it couldn't switch back to this object and *also* + // throw an exception, so the args won't have changed. + + if (PyErr_Occurred()) { + // We get here if we fell of the end of the run() function + // raising an exception. The switch itself was + // successful, but the function raised. + // valgrind reports that memory allocated here can still + // be reached after a test run. + throw PyErrOccurred(); + } + + OwnedObject result; + result <<= this->switch_args; + assert(!this->switch_args); + return result; + } + catch (const PyErrOccurred&) { + /* Turn switch errors into switch throws */ + /* Turn trace errors into switch throws */ + this->release_args(); + throw; + } +} + + +greenlet::PythonAllocator UserGreenlet::allocator; +greenlet::PythonAllocator MainGreenlet::allocator; + + +extern "C" { +static int GREENLET_NOINLINE(slp_save_state_trampoline)(char* stackref) +{ + return switching_thread_state->slp_save_state(stackref); +} +static void GREENLET_NOINLINE(slp_restore_state_trampoline)() +{ + switching_thread_state->slp_restore_state(); +} +} + + + +/***********************************************************/ + +class TracingGuard +{ +private: + PyThreadState* tstate; +public: + TracingGuard() + : tstate(PyThreadState_GET()) + { + PyThreadState_EnterTracing(this->tstate); + } + + ~TracingGuard() + { + PyThreadState_LeaveTracing(this->tstate); + this->tstate = nullptr; + } + + inline void CallTraceFunction(const OwnedObject& tracefunc, + const ImmortalEventName& event, + const BorrowedGreenlet& origin, + const BorrowedGreenlet& target) + { + // TODO: This calls tracefunc(event, (origin, target)). Add a shortcut + // function for that that's specialized to avoid the Py_BuildValue + // string parsing, or start with just using "ON" format with PyTuple_Pack(2, + // origin, target). That seems like what the N format is meant + // for. + // XXX: Why does event not automatically cast back to a PyObject? + // It tries to call the "deleted constructor ImmortalEventName + // const" instead. + assert(tracefunc); + assert(event); + assert(origin); + assert(target); + NewReference retval(PyObject_CallFunction(tracefunc.borrow(), + "O(OO)", + event.borrow(), + origin.borrow(), + target.borrow())); + if (!retval) { + throw PyErrOccurred(); + } + } +}; + +static void +g_calltrace(const OwnedObject& tracefunc, + const ImmortalEventName& event, + const BorrowedGreenlet& origin, + const BorrowedGreenlet& target) +{ + PyErrPieces saved_exc; + try { + TracingGuard tracing_guard; + tracing_guard.CallTraceFunction(tracefunc, event, origin, target); + } + catch (const PyErrOccurred&) { + // In case of exceptions trace function is removed, + // and any existing exception is replaced with the tracing + // exception. + GET_THREAD_STATE().state().set_tracefunc(Py_None); + throw; + } + + saved_exc.PyErrRestore(); +} + + + +static OwnedObject +g_handle_exit(const OwnedObject& greenlet_result) +{ + if (!greenlet_result && mod_globs.PyExc_GreenletExit.PyExceptionMatches()) { + /* catch and ignore GreenletExit */ + PyErrFetchParam val; + PyErr_Fetch(PyErrFetchParam(), val, PyErrFetchParam()); + if (!val) { + return OwnedObject::None(); + } + return OwnedObject(val); + } + + if (greenlet_result) { + // package the result into a 1-tuple + // PyTuple_Pack increments the reference of its arguments, + // so we always need to decref the greenlet result; + // the owner will do that. + return OwnedObject::consuming(PyTuple_Pack(1, greenlet_result.borrow())); + } + + return OwnedObject(); +} + + + +/***********************************************************/ + +static PyGreenlet* +green_new(PyTypeObject* type, PyObject* UNUSED(args), PyObject* UNUSED(kwds)) +{ + PyGreenlet* o = + (PyGreenlet*)PyBaseObject_Type.tp_new(type, mod_globs.empty_tuple, mod_globs.empty_dict); + if (o) { + new UserGreenlet(o, GET_THREAD_STATE().state().borrow_current()); + assert(Py_REFCNT(o) == 1); + } + return o; +} + +static int +green_setrun(BorrowedGreenlet self, BorrowedObject nrun, void* c); +static int +green_setparent(BorrowedGreenlet self, BorrowedObject nparent, void* c); + +static int +green_init(BorrowedGreenlet self, BorrowedObject args, BorrowedObject kwargs) +{ + PyArgParseParam run; + PyArgParseParam nparent; + static const char* const kwlist[] = { + "run", + "parent", + NULL + }; + + // recall: The O specifier does NOT increase the reference count. + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, "|OO:green", (char**)kwlist, &run, &nparent)) { + return -1; + } + + if (run) { + if (green_setrun(self, run, NULL)) { + return -1; + } + } + if (nparent && !nparent.is_None()) { + return green_setparent(self, nparent, NULL); + } + return 0; +} + + +UserGreenlet::ParentIsCurrentGuard::ParentIsCurrentGuard(UserGreenlet* p, + const ThreadState& thread_state) + : oldparent(p->_parent), + greenlet(p) +{ + p->_parent = thread_state.get_current(); +} + +UserGreenlet::ParentIsCurrentGuard::~ParentIsCurrentGuard() +{ + this->greenlet->_parent = oldparent; + oldparent.CLEAR(); +} + + +void +Greenlet::murder_in_place() +{ + if (this->active()) { + assert(!this->is_currently_running_in_some_thread()); + this->deactivate_and_free(); + } +} + +void +UserGreenlet::murder_in_place() +{ + this->_main_greenlet.CLEAR(); + Greenlet::murder_in_place(); +} + +inline void +Greenlet::deactivate_and_free() +{ + if (!this->active()) { + return; + } + // Throw away any saved stack. + this->stack_state = StackState(); + assert(!this->stack_state.active()); + // Throw away any Python references. + // We're holding a borrowed reference to the last + // frame we executed. Since we borrowed it, the + // normal traversal, clear, and dealloc functions + // ignore it, meaning it leaks. (The thread state + // object can't find it to clear it when that's + // deallocated either, because by definition if we + // got an object on this list, it wasn't + // running and the thread state doesn't have + // this frame.) + // So here, we *do* clear it. + this->python_state.tp_clear(true); +} + +bool +Greenlet::belongs_to_thread(const ThreadState* thread_state) const +{ + if (!this->thread_state() // not running anywhere, or thread + // exited + || !thread_state) { // same, or there is no thread state. + return false; + } + return true; +} + +bool +UserGreenlet::belongs_to_thread(const ThreadState* thread_state) const +{ + return Greenlet::belongs_to_thread(thread_state) && this->_main_greenlet == thread_state->borrow_main_greenlet(); +} + +void +Greenlet::deallocing_greenlet_in_thread(const ThreadState* current_thread_state) +{ + /* Cannot raise an exception to kill the greenlet if + it is not running in the same thread! */ + if (this->belongs_to_thread(current_thread_state)) { + assert(current_thread_state); + // To get here it had to have run before + /* Send the greenlet a GreenletExit exception. */ + + // We don't care about the return value, only whether an + // exception happened. + this->throw_GreenletExit_during_dealloc(*current_thread_state); + return; + } + + // Not the same thread! Temporarily save the greenlet + // into its thread's deleteme list, *if* it exists. + // If that thread has already exited, and processed its pending + // cleanup, we'll never be able to clean everything up: we won't + // be able to raise an exception. + // That's mostly OK! Since we can't add it to a list, our refcount + // won't increase, and we'll go ahead with the DECREFs later. + ThreadState *const thread_state = this->thread_state(); + if (thread_state) { + thread_state->delete_when_thread_running(this->self()); + } + else { + // The thread is dead, we can't raise an exception. + // We need to make it look non-active, though, so that dealloc + // finishes killing it. + this->deactivate_and_free(); + } + return; +} + + +int +Greenlet::tp_traverse(visitproc visit, void* arg) +{ + + int result; + if ((result = this->exception_state.tp_traverse(visit, arg)) != 0) { + return result; + } + //XXX: This is ugly. But so is handling everything having to do + //with the top frame. + bool visit_top_frame = this->was_running_in_dead_thread(); + // When true, the thread is dead. Our implicit weak reference to the + // frame is now all that's left; we consider ourselves to + // strongly own it now. + if ((result = this->python_state.tp_traverse(visit, arg, visit_top_frame)) != 0) { + return result; + } + return 0; +} + +int +UserGreenlet::tp_traverse(visitproc visit, void* arg) +{ + Py_VISIT(this->_parent.borrow_o()); + Py_VISIT(this->_main_greenlet.borrow_o()); + Py_VISIT(this->_run_callable.borrow_o()); + + return Greenlet::tp_traverse(visit, arg); +} + +int +MainGreenlet::tp_traverse(visitproc visit, void* arg) +{ + if (this->_thread_state) { + // we've already traversed main, (self), don't do it again. + int result = this->_thread_state->tp_traverse(visit, arg, false); + if (result) { + return result; + } + } + return Greenlet::tp_traverse(visit, arg); +} + +static int +green_traverse(PyGreenlet* self, visitproc visit, void* arg) +{ + // We must only visit referenced objects, i.e. only objects + // Py_INCREF'ed by this greenlet (directly or indirectly): + // + // - stack_prev is not visited: holds previous stack pointer, but it's not + // referenced + // - frames are not visited as we don't strongly reference them; + // alive greenlets are not garbage collected + // anyway. This can be a problem, however, if this greenlet is + // never allowed to finish, and is referenced from the frame: we + // have an uncollectible cycle in that case. Note that the + // frame object itself is also frequently not even tracked by the GC + // starting with Python 3.7 (frames are allocated by the + // interpreter untracked, and only become tracked when their + // evaluation is finished if they have a refcount > 1). All of + // this is to say that we should probably strongly reference + // the frame object. Doing so, while always allowing GC on a + // greenlet, solves several leaks for us. + + Py_VISIT(self->dict); + if (!self->pimpl) { + // Hmm. I have seen this at interpreter shutdown time, + // I think. That's very odd because this doesn't go away until + // we're ``green_dealloc()``, at which point we shouldn't be + // traversed anymore. + return 0; + } + + return self->pimpl->tp_traverse(visit, arg); +} + +static int +green_is_gc(BorrowedGreenlet self) +{ + int result = 0; + /* Main greenlet can be garbage collected since it can only + become unreachable if the underlying thread exited. + Active greenlets --- including those that are suspended --- + cannot be garbage collected, however. + */ + if (self->main() || !self->active()) { + result = 1; + } + // The main greenlet pointer will eventually go away after the thread dies. + if (self->was_running_in_dead_thread()) { + // Our thread is dead! We can never run again. Might as well + // GC us. Note that if a tuple containing only us and other + // immutable objects had been scanned before this, when we + // would have returned 0, the tuple will take itself out of GC + // tracking and never be investigated again. So that could + // result in both us and the tuple leaking due to an + // unreachable/uncollectible reference. The same goes for + // dictionaries. + // + // It's not a great idea to be changing our GC state on the + // fly. + result = 1; + } + return result; +} + + +int +Greenlet::tp_clear() +{ + bool own_top_frame = this->was_running_in_dead_thread(); + this->exception_state.tp_clear(); + this->python_state.tp_clear(own_top_frame); + return 0; +} + +int +UserGreenlet::tp_clear() +{ + Greenlet::tp_clear(); + this->_parent.CLEAR(); + this->_main_greenlet.CLEAR(); + this->_run_callable.CLEAR(); + return 0; +} + + +static int +green_clear(PyGreenlet* self) +{ + /* Greenlet is only cleared if it is about to be collected. + Since active greenlets are not garbage collectable, we can + be sure that, even if they are deallocated during clear, + nothing they reference is in unreachable or finalizers, + so even if it switches we are relatively safe. */ + // XXX: Are we responsible for clearing weakrefs here? + Py_CLEAR(self->dict); + return self->pimpl->tp_clear(); +} + +/** + * Returns 0 on failure (the object was resurrected) or 1 on success. + **/ +static int +_green_dealloc_kill_started_non_main_greenlet(BorrowedGreenlet self) +{ + /* Hacks hacks hacks copied from instance_dealloc() */ + /* Temporarily resurrect the greenlet. */ + assert(self.REFCNT() == 0); + Py_SET_REFCNT(self.borrow(), 1); + /* Save the current exception, if any. */ + PyErrPieces saved_err; + try { + // BY THE TIME WE GET HERE, the state may actually be going + // away + // if we're shutting down the interpreter and freeing thread + // entries, + // this could result in freeing greenlets that were leaked. So + // we can't try to read the state. + self->deallocing_greenlet_in_thread( + self->thread_state() + ? static_cast(GET_THREAD_STATE()) + : nullptr); + } + catch (const PyErrOccurred&) { + PyErr_WriteUnraisable(self.borrow_o()); + /* XXX what else should we do? */ + } + /* Check for no resurrection must be done while we keep + * our internal reference, otherwise PyFile_WriteObject + * causes recursion if using Py_INCREF/Py_DECREF + */ + if (self.REFCNT() == 1 && self->active()) { + /* Not resurrected, but still not dead! + XXX what else should we do? we complain. */ + PyObject* f = PySys_GetObject("stderr"); + Py_INCREF(self.borrow_o()); /* leak! */ + if (f != NULL) { + PyFile_WriteString("GreenletExit did not kill ", f); + PyFile_WriteObject(self.borrow_o(), f, 0); + PyFile_WriteString("\n", f); + } + } + /* Restore the saved exception. */ + saved_err.PyErrRestore(); + /* Undo the temporary resurrection; can't use DECREF here, + * it would cause a recursive call. + */ + assert(self.REFCNT() > 0); + + Py_ssize_t refcnt = self.REFCNT() - 1; + Py_SET_REFCNT(self.borrow_o(), refcnt); + if (refcnt != 0) { + /* Resurrected! */ + _Py_NewReference(self.borrow_o()); + Py_SET_REFCNT(self.borrow_o(), refcnt); + /* Better to use tp_finalizer slot (PEP 442) + * and call ``PyObject_CallFinalizerFromDealloc``, + * but that's only supported in Python 3.4+; see + * Modules/_io/iobase.c for an example. + * + * The following approach is copied from iobase.c in CPython 2.7. + * (along with much of this function in general). Here's their + * comment: + * + * When called from a heap type's dealloc, the type will be + * decref'ed on return (see e.g. subtype_dealloc in typeobject.c). */ + if (PyType_HasFeature(self.TYPE(), Py_TPFLAGS_HEAPTYPE)) { + Py_INCREF(self.TYPE()); + } + + PyObject_GC_Track((PyObject*)self); + + _Py_DEC_REFTOTAL; +#ifdef COUNT_ALLOCS + --Py_TYPE(self)->tp_frees; + --Py_TYPE(self)->tp_allocs; +#endif /* COUNT_ALLOCS */ + return 0; + } + return 1; +} + + +Greenlet::~Greenlet() +{ + // XXX: Can't do this. tp_clear is a virtual function, and by the + // time we're here, we've sliced off our child classes. + //this->tp_clear(); +} + +UserGreenlet::~UserGreenlet() +{ + // Python 3.11: If we don't clear out the raw frame datastack + // when deleting an unfinished greenlet, + // TestLeaks.test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_main fails. + this->python_state.did_finish(nullptr); + this->tp_clear(); +} + +MainGreenlet::~MainGreenlet() +{ + total_main_greenlets--; + this->tp_clear(); +} + +static void +green_dealloc(PyGreenlet* self) +{ + PyObject_GC_UnTrack(self); + BorrowedGreenlet me(self); + if (me->active() + && me->started() + && !me->main()) { + if (!_green_dealloc_kill_started_non_main_greenlet(me)) { + return; + } + } + + if (self->weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject*)self); + } + Py_CLEAR(self->dict); + + if (self->pimpl) { + // In case deleting this, which frees some memory, + // somehow winds up calling back into us. That's usually a + //bug in our code. + Greenlet* p = self->pimpl; + self->pimpl = nullptr; + delete p; + } + // and finally we're done. self is now invalid. + Py_TYPE(self)->tp_free((PyObject*)self); +} + + + +static OwnedObject +throw_greenlet(BorrowedGreenlet self, PyErrPieces& err_pieces) +{ + PyObject* result = nullptr; + err_pieces.PyErrRestore(); + assert(PyErr_Occurred()); + if (self->started() && !self->active()) { + /* dead greenlet: turn GreenletExit into a regular return */ + result = g_handle_exit(OwnedObject()).relinquish_ownership(); + } + + self->args() <<= result; + + return single_result(self->g_switch()); +} + + + +PyDoc_STRVAR( + green_switch_doc, + "switch(*args, **kwargs)\n" + "\n" + "Switch execution to this greenlet.\n" + "\n" + "If this greenlet has never been run, then this greenlet\n" + "will be switched to using the body of ``self.run(*args, **kwargs)``.\n" + "\n" + "If the greenlet is active (has been run, but was switch()'ed\n" + "out before leaving its run function), then this greenlet will\n" + "be resumed and the return value to its switch call will be\n" + "None if no arguments are given, the given argument if one\n" + "argument is given, or the args tuple and keyword args dict if\n" + "multiple arguments are given.\n" + "\n" + "If the greenlet is dead, or is the current greenlet then this\n" + "function will simply return the arguments using the same rules as\n" + "above.\n"); + +static PyObject* +green_switch(PyGreenlet* self, PyObject* args, PyObject* kwargs) +{ + using greenlet::SwitchingArgs; + SwitchingArgs switch_args(OwnedObject::owning(args), OwnedObject::owning(kwargs)); + self->pimpl->args() <<= switch_args; + + + // If we're switching out of a greenlet, and that switch is the + // last thing the greenlet does, the greenlet ought to be able to + // go ahead and die at that point. Currently, someone else must + // manually switch back to the greenlet so that we "fall off the + // end" and can perform cleanup. You'd think we'd be able to + // figure out that this is happening using the frame's ``f_lasti`` + // member, which is supposed to be an index into + // ``frame->f_code->co_code``, the bytecode string. However, in + // recent interpreters, ``f_lasti`` tends not to be updated thanks + // to things like the PREDICT() macros in ceval.c. So it doesn't + // really work to do that in many cases. For example, the Python + // code: + // def run(): + // greenlet.getcurrent().parent.switch() + // produces bytecode of len 16, with the actual call to switch() + // being at index 10 (in Python 3.10). However, the reported + // ``f_lasti`` we actually see is...5! (Which happens to be the + // second byte of the CALL_METHOD op for ``getcurrent()``). + + try { + OwnedObject result = single_result(self->pimpl->g_switch()); +#ifndef NDEBUG + // Note that the current greenlet isn't necessarily self. If self + // finished, we went to one of its parents. + assert(!self->pimpl->args()); + + const BorrowedGreenlet& current = GET_THREAD_STATE().state().borrow_current(); + // It's possible it's never been switched to. + assert(!current->args()); +#endif + return result.relinquish_ownership(); + } + catch(const PyErrOccurred&) { + return nullptr; + } +} + +PyDoc_STRVAR( + green_throw_doc, + "Switches execution to this greenlet, but immediately raises the\n" + "given exception in this greenlet. If no argument is provided, the " + "exception\n" + "defaults to `greenlet.GreenletExit`. The normal exception\n" + "propagation rules apply, as described for `switch`. Note that calling " + "this\n" + "method is almost equivalent to the following::\n" + "\n" + " def raiser():\n" + " raise typ, val, tb\n" + " g_raiser = greenlet(raiser, parent=g)\n" + " g_raiser.switch()\n" + "\n" + "except that this trick does not work for the\n" + "`greenlet.GreenletExit` exception, which would not propagate\n" + "from ``g_raiser`` to ``g``.\n"); + +static PyObject* +green_throw(PyGreenlet* self, PyObject* args) +{ + PyArgParseParam typ(mod_globs.PyExc_GreenletExit); + PyArgParseParam val; + PyArgParseParam tb; + + if (!PyArg_ParseTuple(args, "|OOO:throw", &typ, &val, &tb)) { + return NULL; + } + + try { + // Both normalizing the error and the actual throw_greenlet + // could throw PyErrOccurred. + PyErrPieces err_pieces(typ.borrow(), val.borrow(), tb.borrow()); + + return throw_greenlet(self, err_pieces).relinquish_ownership(); + } + catch (const PyErrOccurred&) { + return nullptr; + } +} + +static int +green_bool(PyGreenlet* self) +{ + return self->pimpl->active(); +} + +static PyObject* +green_getdict(PyGreenlet* self, void* UNUSED(context)) +{ + if (self->dict == NULL) { + self->dict = PyDict_New(); + if (self->dict == NULL) { + return NULL; + } + } + Py_INCREF(self->dict); + return self->dict; +} + +static int +green_setdict(PyGreenlet* self, PyObject* val, void* UNUSED(context)) +{ + PyObject* tmp; + + if (val == NULL) { + PyErr_SetString(PyExc_TypeError, "__dict__ may not be deleted"); + return -1; + } + if (!PyDict_Check(val)) { + PyErr_SetString(PyExc_TypeError, "__dict__ must be a dictionary"); + return -1; + } + tmp = self->dict; + Py_INCREF(val); + self->dict = val; + Py_XDECREF(tmp); + return 0; +} + +static bool +_green_not_dead(BorrowedGreenlet self) +{ + // XXX: Where else should we do this? + // Probably on entry to most Python-facing functions? + if (self->was_running_in_dead_thread()) { + self->deactivate_and_free(); + return false; + } + return self->active() || !self->started(); +} + + +static PyObject* +green_getdead(BorrowedGreenlet self, void* UNUSED(context)) +{ + if (_green_not_dead(self)) { + Py_RETURN_FALSE; + } + else { + Py_RETURN_TRUE; + } +} + +static PyObject* +green_get_stack_saved(PyGreenlet* self, void* UNUSED(context)) +{ + return PyLong_FromSsize_t(self->pimpl->stack_saved()); +} + + +static PyObject* +green_getrun(BorrowedGreenlet self, void* UNUSED(context)) +{ + try { + OwnedObject result(self->run()); + return result.relinquish_ownership(); + } + catch(const PyErrOccurred&) { + return nullptr; + } +} + +void +UserGreenlet::run(const BorrowedObject nrun) +{ + if (this->started()) { + throw AttributeError( + "run cannot be set " + "after the start of the greenlet"); + } + this->_run_callable = nrun; +} + +const OwnedObject& +MainGreenlet::run() const +{ + throw AttributeError("Main greenlets do not have a run attribute."); +} + +void +MainGreenlet::run(const BorrowedObject UNUSED(nrun)) +{ + throw AttributeError("Main greenlets do not have a run attribute."); +} + +static int +green_setrun(BorrowedGreenlet self, BorrowedObject nrun, void* UNUSED(context)) +{ + try { + self->run(nrun); + return 0; + } + catch(const PyErrOccurred&) { + return -1; + } +} + +static PyObject* +green_getparent(BorrowedGreenlet self, void* UNUSED(context)) +{ + return self->parent().acquire_or_None(); +} + +using greenlet::AttributeError; + +const OwnedGreenlet +UserGreenlet::parent() const +{ + return this->_parent; +} + +void +UserGreenlet::parent(const BorrowedObject raw_new_parent) +{ + if (!raw_new_parent) { + throw AttributeError("can't delete attribute"); + } + + BorrowedMainGreenlet main_greenlet_of_new_parent; + BorrowedGreenlet new_parent(raw_new_parent.borrow()); // could + // throw + // TypeError! + for (BorrowedGreenlet p = new_parent; p; p = p->parent()) { + if (p == this->_self) { + throw ValueError("cyclic parent chain"); + } + main_greenlet_of_new_parent = p->main_greenlet(); + } + + if (!main_greenlet_of_new_parent) { + throw ValueError("parent must not be garbage collected"); + } + + if (this->started() + && this->_main_greenlet != main_greenlet_of_new_parent) { + throw ValueError("parent cannot be on a different thread"); + } + + this->_parent = new_parent; +} + +void +MainGreenlet::parent(const BorrowedObject raw_new_parent) +{ + if (!raw_new_parent) { + throw AttributeError("can't delete attribute"); + } + throw AttributeError("cannot set the parent of a main greenlet"); +} + +const OwnedGreenlet +MainGreenlet::parent() const +{ + return OwnedGreenlet(); // null becomes None +} + +static int +green_setparent(BorrowedGreenlet self, BorrowedObject nparent, void* UNUSED(context)) +{ + try { + self->parent(nparent); + } + catch(const PyErrOccurred&) { + return -1; + } + return 0; +} + +#ifdef Py_CONTEXT_H +# define GREENLET_NO_CONTEXTVARS_REASON "This build of greenlet" +#else +# define GREENLET_NO_CONTEXTVARS_REASON "This Python interpreter" +#endif + +namespace greenlet +{ + +template<> +const OwnedObject +Greenlet::context(GREENLET_WHEN_PY37::Yes) const +{ + using greenlet::PythonStateContext; + OwnedObject result; + + if (this->is_currently_running_in_some_thread()) { + /* Currently running greenlet: context is stored in the thread state, + not the greenlet object. */ + if (GET_THREAD_STATE().state().is_current(this->self())) { + result = PythonStateContext::context(PyThreadState_GET()); + } + else { + throw ValueError( + "cannot get context of a " + "greenlet that is running in a different thread"); + } + } + else { + /* Greenlet is not running: just return context. */ + result = this->python_state.context(); + } + if (!result) { + result = OwnedObject::None(); + } + return result; +} + +template<> +const OwnedObject +Greenlet::context(GREENLET_WHEN_NOT_PY37::No) const +{ + throw AttributeError( + GREENLET_NO_CONTEXTVARS_REASON + "does not support context variables" + ); +} + +template<> +void Greenlet::context(BorrowedObject given, GREENLET_WHEN_PY37::Yes) +{ + using greenlet::PythonStateContext; + if (!given) { + throw AttributeError("can't delete context attribute"); + } + if (given.is_None()) { + /* "Empty context" is stored as NULL, not None. */ + given = nullptr; + } + + //checks type, incrs refcnt + greenlet::refs::OwnedContext context(given); + PyThreadState* tstate = PyThreadState_GET(); + + if (this->is_currently_running_in_some_thread()) { + if (!GET_THREAD_STATE().state().is_current(this->self())) { + throw ValueError("cannot set context of a greenlet" + " that is running in a different thread"); + } + + /* Currently running greenlet: context is stored in the thread state, + not the greenlet object. */ + OwnedObject octx = OwnedObject::consuming(PythonStateContext::context(tstate)); + PythonStateContext::context(tstate, context.relinquish_ownership()); + } + else { + /* Greenlet is not running: just set context. Note that the + greenlet may be dead.*/ + this->python_state.context() = context; + } +} + +template<> +void +Greenlet::context(BorrowedObject UNUSED(given), GREENLET_WHEN_NOT_PY37::No) +{ + throw AttributeError( + GREENLET_NO_CONTEXTVARS_REASON + "does not support context variables" + ); +} + +}; + +static PyObject* +green_getcontext(const PyGreenlet* self, void* UNUSED(context)) +{ + const Greenlet *const g = self->pimpl; + try { + OwnedObject result(g->context()); + return result.relinquish_ownership(); + } + catch(const PyErrOccurred&) { + return nullptr; + } +} + +static int +green_setcontext(BorrowedGreenlet self, PyObject* nctx, void* UNUSED(context)) +{ + try { + self->context(nctx, G_IS_PY37::IsIt()); + return 0; + } + catch(const PyErrOccurred&) { + return -1; + } +} + +#undef GREENLET_NO_CONTEXTVARS_REASON + +static PyObject* +green_getframe(BorrowedGreenlet self, void* UNUSED(context)) +{ + const PythonState::OwnedFrame& top_frame = self->top_frame(); + return top_frame.acquire_or_None(); +} + +static PyObject* +green_getstate(PyGreenlet* self) +{ + PyErr_Format(PyExc_TypeError, + "cannot serialize '%s' object", + Py_TYPE(self)->tp_name); + return nullptr; +} + +static PyObject* +green_repr(BorrowedGreenlet self) +{ + /* + Return a string like + + + The handling of greenlets across threads is not super good. + We mostly use the internal definitions of these terms, but they + generally should make sense to users as well. + */ + PyObject* result; + int never_started = !self->started() && !self->active(); + + const char* const tp_name = Py_TYPE(self)->tp_name; + + if (_green_not_dead(self)) { + /* XXX: The otid= is almost useless because you can't correlate it to + any thread identifier exposed to Python. We could use + PyThreadState_GET()->thread_id, but we'd need to save that in the + greenlet, or save the whole PyThreadState object itself. + + As it stands, its only useful for identifying greenlets from the same thread. + */ + const char* state_in_thread; + if (self->was_running_in_dead_thread()) { + // The thread it was running in is dead! + // This can happen, especially at interpreter shut down. + // It complicates debugging output because it may be + // impossible to access the current thread state at that + // time. Thus, don't access the current thread state. + state_in_thread = " (thread exited)"; + } + else { + state_in_thread = GET_THREAD_STATE().state().is_current(self) + ? " current" + : (self->started() ? " suspended" : ""); + } + result = GNative_FromFormat( + "<%s object at %p (otid=%p)%s%s%s%s>", + tp_name, + self.borrow_o(), + self->thread_state(), + state_in_thread, + self->active() ? " active" : "", + never_started ? " pending" : " started", + self->main() ? " main" : "" + ); + } + else { + result = GNative_FromFormat( + "<%s object at %p (otid=%p) %sdead>", + tp_name, + self.borrow_o(), + self->thread_state(), + self->was_running_in_dead_thread() + ? "(thread exited) " + : "" + ); + } + + return result; +} + +/***************************************************************************** + * C interface + * + * These are exported using the CObject API + */ +extern "C" { +static PyGreenlet* +PyGreenlet_GetCurrent(void) +{ + return GET_THREAD_STATE().state().get_current().relinquish_ownership(); +} + +static int +PyGreenlet_SetParent(PyGreenlet* g, PyGreenlet* nparent) +{ + return green_setparent((PyGreenlet*)g, (PyObject*)nparent, NULL); +} + +static PyGreenlet* +PyGreenlet_New(PyObject* run, PyGreenlet* parent) +{ + using greenlet::refs::NewDictReference; + // In the past, we didn't use green_new and green_init, but that + // was a maintenance issue because we duplicated code. This way is + // much safer, but slightly slower. If that's a problem, we could + // refactor green_init to separate argument parsing from initialization. + OwnedGreenlet g = OwnedGreenlet::consuming(green_new(&PyGreenlet_Type, nullptr, nullptr)); + if (!g) { + return NULL; + } + + try { + NewDictReference kwargs; + if (run) { + kwargs.SetItem(mod_globs.str_run, run); + } + if (parent) { + kwargs.SetItem("parent", (PyObject*)parent); + } + + Require(green_init(g, mod_globs.empty_tuple, kwargs)); + } + catch (const PyErrOccurred&) { + return nullptr; + } + + return g.relinquish_ownership(); +} + +static PyObject* +PyGreenlet_Switch(PyGreenlet* g, PyObject* args, PyObject* kwargs) +{ + PyGreenlet* self = (PyGreenlet*)g; + + if (!PyGreenlet_Check(self)) { + PyErr_BadArgument(); + return NULL; + } + + if (args == NULL) { + args = mod_globs.empty_tuple; + } + + if (kwargs == NULL || !PyDict_Check(kwargs)) { + kwargs = NULL; + } + + return green_switch(g, args, kwargs); +} + +static PyObject* +PyGreenlet_Throw(PyGreenlet* self, PyObject* typ, PyObject* val, PyObject* tb) +{ + if (!PyGreenlet_Check(self)) { + PyErr_BadArgument(); + return nullptr; + } + try { + PyErrPieces err_pieces(typ, val, tb); + return throw_greenlet(self, err_pieces).relinquish_ownership(); + } + catch (const PyErrOccurred&) { + return nullptr; + } +} + +static int +Extern_PyGreenlet_MAIN(PyGreenlet* self) +{ + if (!PyGreenlet_Check(self)) { + PyErr_BadArgument(); + return -1; + } + return self->pimpl->main(); +} + +static int +Extern_PyGreenlet_ACTIVE(PyGreenlet* self) +{ + if (!PyGreenlet_Check(self)) { + PyErr_BadArgument(); + return -1; + } + return self->pimpl->active(); +} + +static int +Extern_PyGreenlet_STARTED(PyGreenlet* self) +{ + if (!PyGreenlet_Check(self)) { + PyErr_BadArgument(); + return -1; + } + return self->pimpl->started(); +} + +static PyGreenlet* +Extern_PyGreenlet_GET_PARENT(PyGreenlet* self) +{ + if (!PyGreenlet_Check(self)) { + PyErr_BadArgument(); + return NULL; + } + // This can return NULL even if there is no exception + return self->pimpl->parent().acquire(); +} +} // extern C. +/** End C API ****************************************************************/ + +static PyMethodDef green_methods[] = { + {"switch", + reinterpret_cast(green_switch), + METH_VARARGS | METH_KEYWORDS, + green_switch_doc}, + {"throw", (PyCFunction)green_throw, METH_VARARGS, green_throw_doc}, + {"__getstate__", (PyCFunction)green_getstate, METH_NOARGS, NULL}, + {NULL, NULL} /* sentinel */ +}; + +static PyGetSetDef green_getsets[] = { + {"__dict__", (getter)green_getdict, (setter)green_setdict, /*XXX*/ NULL}, + {"run", (getter)green_getrun, (setter)green_setrun, /*XXX*/ NULL}, + {"parent", (getter)green_getparent, (setter)green_setparent, /*XXX*/ NULL}, + {"gr_frame", (getter)green_getframe, NULL, /*XXX*/ NULL}, + {"gr_context", + (getter)green_getcontext, + (setter)green_setcontext, + /*XXX*/ NULL}, + {"dead", (getter)green_getdead, NULL, /*XXX*/ NULL}, + {"_stack_saved", (getter)green_get_stack_saved, NULL, /*XXX*/ NULL}, + {NULL}}; + +static PyMemberDef green_members[] = { + {NULL} +}; + +static PyNumberMethods green_as_number = { + NULL, /* nb_add */ + NULL, /* nb_subtract */ + NULL, /* nb_multiply */ +#if PY_MAJOR_VERSION < 3 + NULL, /* nb_divide */ +#endif + NULL, /* nb_remainder */ + NULL, /* nb_divmod */ + NULL, /* nb_power */ + NULL, /* nb_negative */ + NULL, /* nb_positive */ + NULL, /* nb_absolute */ + (inquiry)green_bool, /* nb_bool */ +}; + + +PyTypeObject PyGreenlet_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "greenlet.greenlet", /* tp_name */ + sizeof(PyGreenlet), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)green_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)green_repr, /* tp_repr */ + &green_as_number, /* tp_as _number*/ + 0, /* tp_as _sequence*/ + 0, /* tp_as _mapping*/ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer*/ + G_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "greenlet(run=None, parent=None) -> greenlet\n\n" + "Creates a new greenlet object (without running it).\n\n" + " - *run* -- The callable to invoke.\n" + " - *parent* -- The parent greenlet. The default is the current " + "greenlet.", /* tp_doc */ + (traverseproc)green_traverse, /* tp_traverse */ + (inquiry)green_clear, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(PyGreenlet, weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + green_methods, /* tp_methods */ + green_members, /* tp_members */ + green_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof(PyGreenlet, dict), /* tp_dictoffset */ + (initproc)green_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + (newfunc)green_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ + (inquiry)green_is_gc, /* tp_is_gc */ +}; + + + +PyDoc_STRVAR(mod_getcurrent_doc, + "getcurrent() -> greenlet\n" + "\n" + "Returns the current greenlet (i.e. the one which called this " + "function).\n"); + +static PyObject* +mod_getcurrent(PyObject* UNUSED(module)) +{ + return GET_THREAD_STATE().state().get_current().relinquish_ownership_o(); +} + +PyDoc_STRVAR(mod_settrace_doc, + "settrace(callback) -> object\n" + "\n" + "Sets a new tracing function and returns the previous one.\n"); +static PyObject* +mod_settrace(PyObject* UNUSED(module), PyObject* args) +{ + PyArgParseParam tracefunc; + if (!PyArg_ParseTuple(args, "O", &tracefunc)) { + return NULL; + } + ThreadState& state = GET_THREAD_STATE(); + OwnedObject previous = state.get_tracefunc(); + if (!previous) { + previous = Py_None; + } + + state.set_tracefunc(tracefunc); + + return previous.relinquish_ownership(); +} + +PyDoc_STRVAR(mod_gettrace_doc, + "gettrace() -> object\n" + "\n" + "Returns the currently set tracing function, or None.\n"); + +static PyObject* +mod_gettrace(PyObject* UNUSED(module)) +{ + OwnedObject tracefunc = GET_THREAD_STATE().state().get_tracefunc(); + if (!tracefunc) { + tracefunc = Py_None; + } + return tracefunc.relinquish_ownership(); +} + +PyDoc_STRVAR(mod_set_thread_local_doc, + "set_thread_local(key, value) -> None\n" + "\n" + "Set a value in the current thread-local dictionary. Debbuging only.\n"); + +static PyObject* +mod_set_thread_local(PyObject* UNUSED(module), PyObject* args) +{ + PyArgParseParam key; + PyArgParseParam value; + PyObject* result = NULL; + + if (PyArg_UnpackTuple(args, "set_thread_local", 2, 2, &key, &value)) { + if(PyDict_SetItem( + PyThreadState_GetDict(), // borrow + key, + value) == 0 ) { + // success + Py_INCREF(Py_None); + result = Py_None; + } + } + return result; +} + +PyDoc_STRVAR(mod_get_pending_cleanup_count_doc, + "get_pending_cleanup_count() -> Integer\n" + "\n" + "Get the number of greenlet cleanup operations pending. Testing only.\n"); + + +static PyObject* +mod_get_pending_cleanup_count(PyObject* UNUSED(module)) +{ + LockGuard cleanup_lock(*mod_globs.thread_states_to_destroy_lock); + return PyLong_FromSize_t(mod_globs.thread_states_to_destroy.size()); +} + +PyDoc_STRVAR(mod_get_total_main_greenlets_doc, + "get_total_main_greenlets() -> Integer\n" + "\n" + "Quickly return the number of main greenlets that exist. Testing only.\n"); + +static PyObject* +mod_get_total_main_greenlets(PyObject* UNUSED(module)) +{ + return PyLong_FromSize_t(total_main_greenlets); +} + +PyDoc_STRVAR(mod_get_clocks_used_doing_optional_cleanup_doc, + "get_clocks_used_doing_optional_cleanup() -> Integer\n" + "\n" + "Get the number of clock ticks the program has used doing optional " + "greenlet cleanup.\n" + "Beginning in greenlet 2.0, greenlet tries to find and dispose of greenlets\n" + "that leaked after a thread exited. This requires invoking Python's garbage collector,\n" + "which may have a performance cost proportional to the number of live objects.\n" + "This function returns the amount of processor time\n" + "greenlet has used to do this. In programs that run with very large amounts of live\n" + "objects, this metric can be used to decide whether the cost of doing this cleanup\n" + "is worth the memory leak being corrected. If not, you can disable the cleanup\n" + "using ``enable_optional_cleanup(False)``.\n" + "The units are arbitrary and can only be compared to themselves (similarly to ``time.clock()``);\n" + "for example, to see how it scales with your heap. You can attempt to convert them into seconds\n" + "by dividing by the value of CLOCKS_PER_SEC." + "If cleanup has been disabled, returns None." + "\n" + "This is an implementation specific, provisional API. It may be changed or removed\n" + "in the future.\n" + ".. versionadded:: 2.0" + ); +static PyObject* +mod_get_clocks_used_doing_optional_cleanup(PyObject* UNUSED(module)) +{ + std::clock_t& clocks = ThreadState::clocks_used_doing_gc(); + + if (clocks == std::clock_t(-1)) { + Py_RETURN_NONE; + } + // This might not actually work on some implementations; clock_t + // is an opaque type. + return PyLong_FromSsize_t(clocks); +} + +PyDoc_STRVAR(mod_enable_optional_cleanup_doc, + "mod_enable_optional_cleanup(bool) -> None\n" + "\n" + "Enable or disable optional cleanup operations.\n" + "See ``get_clocks_used_doing_optional_cleanup()`` for details.\n" + ); +static PyObject* +mod_enable_optional_cleanup(PyObject* UNUSED(module), PyObject* flag) +{ + int is_true = PyObject_IsTrue(flag); + if (is_true == -1) { + return nullptr; + } + + std::clock_t& clocks = ThreadState::clocks_used_doing_gc(); + if (is_true) { + // If we already have a value, we don't want to lose it. + if (clocks == std::clock_t(-1)) { + clocks = 0; + } + } + else { + clocks = std::clock_t(-1); + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(mod_get_tstate_trash_delete_nesting_doc, + "get_tstate_trash_delete_nesting() -> Integer\n" + "\n" + "Return the 'trash can' nesting level. Testing only.\n"); +static PyObject* +mod_get_tstate_trash_delete_nesting(PyObject* UNUSED(module)) +{ + PyThreadState* tstate = PyThreadState_GET(); + return PyLong_FromLong(tstate->trash_delete_nesting); +} + +static PyMethodDef GreenMethods[] = { + {"getcurrent", + (PyCFunction)mod_getcurrent, + METH_NOARGS, + mod_getcurrent_doc}, + {"settrace", (PyCFunction)mod_settrace, METH_VARARGS, mod_settrace_doc}, + {"gettrace", (PyCFunction)mod_gettrace, METH_NOARGS, mod_gettrace_doc}, + {"set_thread_local", (PyCFunction)mod_set_thread_local, METH_VARARGS, mod_set_thread_local_doc}, + {"get_pending_cleanup_count", (PyCFunction)mod_get_pending_cleanup_count, METH_NOARGS, mod_get_pending_cleanup_count_doc}, + {"get_total_main_greenlets", (PyCFunction)mod_get_total_main_greenlets, METH_NOARGS, mod_get_total_main_greenlets_doc}, + {"get_clocks_used_doing_optional_cleanup", (PyCFunction)mod_get_clocks_used_doing_optional_cleanup, METH_NOARGS, mod_get_clocks_used_doing_optional_cleanup_doc}, + {"enable_optional_cleanup", (PyCFunction)mod_enable_optional_cleanup, METH_O, mod_enable_optional_cleanup_doc}, + {"get_tstate_trash_delete_nesting", (PyCFunction)mod_get_tstate_trash_delete_nesting, METH_NOARGS, mod_get_tstate_trash_delete_nesting_doc}, + {NULL, NULL} /* Sentinel */ +}; + +static const char* const copy_on_greentype[] = { + "getcurrent", + "error", + "GreenletExit", + "settrace", + "gettrace", + NULL +}; + +static struct PyModuleDef greenlet_module_def = { + PyModuleDef_HEAD_INIT, + "greenlet._greenlet", + NULL, + -1, + GreenMethods, +}; + + + +static PyObject* +greenlet_internal_mod_init() G_NOEXCEPT +{ + static void* _PyGreenlet_API[PyGreenlet_API_pointers]; + GREENLET_NOINLINE_INIT(); + + try { + CreatedModule m(greenlet_module_def); + + Require(PyType_Ready(&PyGreenlet_Type)); + +#if G_USE_STANDARD_THREADING == 0 + Require(PyType_Ready(&PyGreenletCleanup_Type)); +#endif + + new((void*)&mod_globs) GreenletGlobals; + ThreadState::init(); + + m.PyAddObject("greenlet", PyGreenlet_Type); + m.PyAddObject("error", mod_globs.PyExc_GreenletError); + m.PyAddObject("GreenletExit", mod_globs.PyExc_GreenletExit); + + m.PyAddObject("GREENLET_USE_GC", 1); + m.PyAddObject("GREENLET_USE_TRACING", 1); + // The macros are eithre 0 or 1; the 0 case can be interpreted + // the same as NULL, which is ambiguous with a pointer. + m.PyAddObject("GREENLET_USE_CONTEXT_VARS", (long)GREENLET_PY37); + m.PyAddObject("GREENLET_USE_STANDARD_THREADING", (long)G_USE_STANDARD_THREADING); + + OwnedObject clocks_per_sec = OwnedObject::consuming(PyLong_FromSsize_t(CLOCKS_PER_SEC)); + m.PyAddObject("CLOCKS_PER_SEC", clocks_per_sec); + + /* also publish module-level data as attributes of the greentype. */ + // XXX: This is weird, and enables a strange pattern of + // confusing the class greenlet with the module greenlet; with + // the exception of (possibly) ``getcurrent()``, this + // shouldn't be encouraged so don't add new items here. + for (const char* const* p = copy_on_greentype; *p; p++) { + OwnedObject o = m.PyRequireAttr(*p); + PyDict_SetItemString(PyGreenlet_Type.tp_dict, *p, o.borrow()); + } + + /* + * Expose C API + */ + + /* types */ + _PyGreenlet_API[PyGreenlet_Type_NUM] = (void*)&PyGreenlet_Type; + + /* exceptions */ + _PyGreenlet_API[PyExc_GreenletError_NUM] = (void*)mod_globs.PyExc_GreenletError; + _PyGreenlet_API[PyExc_GreenletExit_NUM] = (void*)mod_globs.PyExc_GreenletExit; + + /* methods */ + _PyGreenlet_API[PyGreenlet_New_NUM] = (void*)PyGreenlet_New; + _PyGreenlet_API[PyGreenlet_GetCurrent_NUM] = (void*)PyGreenlet_GetCurrent; + _PyGreenlet_API[PyGreenlet_Throw_NUM] = (void*)PyGreenlet_Throw; + _PyGreenlet_API[PyGreenlet_Switch_NUM] = (void*)PyGreenlet_Switch; + _PyGreenlet_API[PyGreenlet_SetParent_NUM] = (void*)PyGreenlet_SetParent; + + /* Previously macros, but now need to be functions externally. */ + _PyGreenlet_API[PyGreenlet_MAIN_NUM] = (void*)Extern_PyGreenlet_MAIN; + _PyGreenlet_API[PyGreenlet_STARTED_NUM] = (void*)Extern_PyGreenlet_STARTED; + _PyGreenlet_API[PyGreenlet_ACTIVE_NUM] = (void*)Extern_PyGreenlet_ACTIVE; + _PyGreenlet_API[PyGreenlet_GET_PARENT_NUM] = (void*)Extern_PyGreenlet_GET_PARENT; + + /* XXX: Note that our module name is ``greenlet._greenlet``, but for + backwards compatibility with existing C code, we need the _C_API to + be directly in greenlet. + */ + const NewReference c_api_object(Require( + PyCapsule_New( + (void*)_PyGreenlet_API, + "greenlet._C_API", + NULL))); + m.PyAddObject("_C_API", c_api_object); + assert(c_api_object.REFCNT() == 2); + + // cerr << "Sizes:" + // << "\n\tGreenlet : " << sizeof(Greenlet) + // << "\n\tUserGreenlet : " << sizeof(UserGreenlet) + // << "\n\tMainGreenlet : " << sizeof(MainGreenlet) + // << "\n\tExceptionState : " << sizeof(greenlet::ExceptionState) + // << "\n\tPythonState : " << sizeof(greenlet::PythonState) + // << "\n\tStackState : " << sizeof(greenlet::StackState) + // << "\n\tSwitchingArgs : " << sizeof(greenlet::SwitchingArgs) + // << "\n\tOwnedObject : " << sizeof(greenlet::refs::OwnedObject) + // << "\n\tBorrowedObject : " << sizeof(greenlet::refs::BorrowedObject) + // << "\n\tPyGreenlet : " << sizeof(PyGreenlet) + // << endl; + + return m.borrow(); // But really it's the main reference. + } + catch (const LockInitError& e) { + PyErr_SetString(PyExc_MemoryError, e.what()); + return NULL; + } + catch (const PyErrOccurred&) { + return NULL; + } + +} + +extern "C" { +#if PY_MAJOR_VERSION >= 3 +PyMODINIT_FUNC +PyInit__greenlet(void) +{ + return greenlet_internal_mod_init(); +} +#else +PyMODINIT_FUNC +init_greenlet(void) +{ + greenlet_internal_mod_init(); +} +#endif +}; + +#ifdef __clang__ +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#endif diff --git a/.venv/Lib/site-packages/greenlet/greenlet.h b/.venv/Lib/site-packages/greenlet/greenlet.h new file mode 100644 index 000000000..d02a16e43 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/greenlet.h @@ -0,0 +1,164 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ + +/* Greenlet object interface */ + +#ifndef Py_GREENLETOBJECT_H +#define Py_GREENLETOBJECT_H + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is deprecated and undocumented. It does not change. */ +#define GREENLET_VERSION "1.0.0" + +#ifndef GREENLET_MODULE +#define implementation_ptr_t void* +#endif + +typedef struct _greenlet { + PyObject_HEAD + PyObject* weakreflist; + PyObject* dict; + implementation_ptr_t pimpl; +} PyGreenlet; + +#define PyGreenlet_Check(op) (op && PyObject_TypeCheck(op, &PyGreenlet_Type)) + + +/* C API functions */ + +/* Total number of symbols that are exported */ +#define PyGreenlet_API_pointers 12 + +#define PyGreenlet_Type_NUM 0 +#define PyExc_GreenletError_NUM 1 +#define PyExc_GreenletExit_NUM 2 + +#define PyGreenlet_New_NUM 3 +#define PyGreenlet_GetCurrent_NUM 4 +#define PyGreenlet_Throw_NUM 5 +#define PyGreenlet_Switch_NUM 6 +#define PyGreenlet_SetParent_NUM 7 + +#define PyGreenlet_MAIN_NUM 8 +#define PyGreenlet_STARTED_NUM 9 +#define PyGreenlet_ACTIVE_NUM 10 +#define PyGreenlet_GET_PARENT_NUM 11 + +#ifndef GREENLET_MODULE +/* This section is used by modules that uses the greenlet C API */ +static void** _PyGreenlet_API = NULL; + +# define PyGreenlet_Type \ + (*(PyTypeObject*)_PyGreenlet_API[PyGreenlet_Type_NUM]) + +# define PyExc_GreenletError \ + ((PyObject*)_PyGreenlet_API[PyExc_GreenletError_NUM]) + +# define PyExc_GreenletExit \ + ((PyObject*)_PyGreenlet_API[PyExc_GreenletExit_NUM]) + +/* + * PyGreenlet_New(PyObject *args) + * + * greenlet.greenlet(run, parent=None) + */ +# define PyGreenlet_New \ + (*(PyGreenlet * (*)(PyObject * run, PyGreenlet * parent)) \ + _PyGreenlet_API[PyGreenlet_New_NUM]) + +/* + * PyGreenlet_GetCurrent(void) + * + * greenlet.getcurrent() + */ +# define PyGreenlet_GetCurrent \ + (*(PyGreenlet * (*)(void)) _PyGreenlet_API[PyGreenlet_GetCurrent_NUM]) + +/* + * PyGreenlet_Throw( + * PyGreenlet *greenlet, + * PyObject *typ, + * PyObject *val, + * PyObject *tb) + * + * g.throw(...) + */ +# define PyGreenlet_Throw \ + (*(PyObject * (*)(PyGreenlet * self, \ + PyObject * typ, \ + PyObject * val, \ + PyObject * tb)) \ + _PyGreenlet_API[PyGreenlet_Throw_NUM]) + +/* + * PyGreenlet_Switch(PyGreenlet *greenlet, PyObject *args) + * + * g.switch(*args, **kwargs) + */ +# define PyGreenlet_Switch \ + (*(PyObject * \ + (*)(PyGreenlet * greenlet, PyObject * args, PyObject * kwargs)) \ + _PyGreenlet_API[PyGreenlet_Switch_NUM]) + +/* + * PyGreenlet_SetParent(PyObject *greenlet, PyObject *new_parent) + * + * g.parent = new_parent + */ +# define PyGreenlet_SetParent \ + (*(int (*)(PyGreenlet * greenlet, PyGreenlet * nparent)) \ + _PyGreenlet_API[PyGreenlet_SetParent_NUM]) + +/* + * PyGreenlet_GetParent(PyObject* greenlet) + * + * return greenlet.parent; + * + * This could return NULL even if there is no exception active. + * If it does not return NULL, you are responsible for decrementing the + * reference count. + */ +# define PyGreenlet_GetParent \ + (*(PyGreenlet* (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_GET_PARENT_NUM]) + +/* + * deprecated, undocumented alias. + */ +# define PyGreenlet_GET_PARENT PyGreenlet_GetParent + +# define PyGreenlet_MAIN \ + (*(int (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_MAIN_NUM]) + +# define PyGreenlet_STARTED \ + (*(int (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_STARTED_NUM]) + +# define PyGreenlet_ACTIVE \ + (*(int (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_ACTIVE_NUM]) + + + + +/* Macro that imports greenlet and initializes C API */ +/* NOTE: This has actually moved to ``greenlet._greenlet._C_API``, but we + keep the older definition to be sure older code that might have a copy of + the header still works. */ +# define PyGreenlet_Import() \ + { \ + _PyGreenlet_API = (void**)PyCapsule_Import("greenlet._C_API", 0); \ + } + +#endif /* GREENLET_MODULE */ + +#ifdef __cplusplus +} +#endif +#endif /* !Py_GREENLETOBJECT_H */ diff --git a/.venv/Lib/site-packages/greenlet/greenlet_allocator.hpp b/.venv/Lib/site-packages/greenlet/greenlet_allocator.hpp new file mode 100644 index 000000000..b452f5444 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/greenlet_allocator.hpp @@ -0,0 +1,63 @@ +#ifndef GREENLET_ALLOCATOR_HPP +#define GREENLET_ALLOCATOR_HPP + +#define PY_SSIZE_T_CLEAN +#include +#include +#include "greenlet_compiler_compat.hpp" + + +namespace greenlet +{ + // This allocator is stateless; all instances are identical. + // It can *ONLY* be used when we're sure we're holding the GIL + // (Python's allocators require the GIL). + template + struct PythonAllocator : public std::allocator { + + PythonAllocator(const PythonAllocator& UNUSED(other)) + : std::allocator() + { + } + + PythonAllocator(const std::allocator other) + : std::allocator(other) + {} + + template + PythonAllocator(const std::allocator& other) + : std::allocator(other) + { + } + + PythonAllocator() : std::allocator() {} + + T* allocate(size_t number_objects, const void* UNUSED(hint)=0) + { + void* p; + if (number_objects == 1) + p = PyObject_Malloc(sizeof(T)); + else + p = PyMem_Malloc(sizeof(T) * number_objects); + return static_cast(p); + } + + void deallocate(T* t, size_t n) + { + void* p = t; + if (n == 1) { + PyObject_Free(p); + } + else + PyMem_Free(p); + } + // This member is deprecated in C++17 and removed in C++20 + template< class U > + struct rebind { + typedef PythonAllocator other; + }; + + }; +} + +#endif diff --git a/.venv/Lib/site-packages/greenlet/greenlet_compiler_compat.hpp b/.venv/Lib/site-packages/greenlet/greenlet_compiler_compat.hpp new file mode 100644 index 000000000..ecaeb3263 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/greenlet_compiler_compat.hpp @@ -0,0 +1,132 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +#ifndef GREENLET_COMPILER_COMPAT_HPP +#define GREENLET_COMPILER_COMPAT_HPP + +/** + * Definitions to aid with compatibility with different compilers. + * + * .. caution:: Use extreme care with G_NOEXCEPT. + * Some compilers and runtimes, specifically gcc/libgcc/libstdc++ on + * Linux, implement stack unwinding by throwing an uncatchable + * exception, one that specifically does not appear to be an active + * exception to the rest of the runtime. If this happens while we're in a G_NOEXCEPT function, + * we have violated our dynamic exception contract, and so the runtime + * will call std::terminate(), which kills the process with the + * unhelpful message "terminate called without an active exception". + * + * This has happened in this scenario: A background thread is running + * a greenlet that has made a native call and released the GIL. + * Meanwhile, the main thread finishes and starts shutting down the + * interpreter. When the background thread is scheduled again and + * attempts to obtain the GIL, it notices that the interpreter is + * exiting and calls ``pthread_exit()``. This in turn starts to unwind + * the stack by throwing that exception. But we had the ``PyCall`` + * functions annotated as G_NOEXCEPT, so the runtime terminated us. + * + * #2 0x00007fab26fec2b7 in std::terminate() () from /lib/x86_64-linux-gnu/libstdc++.so.6 + * #3 0x00007fab26febb3c in __gxx_personality_v0 () from /lib/x86_64-linux-gnu/libstdc++.so.6 + * #4 0x00007fab26f34de6 in ?? () from /lib/x86_64-linux-gnu/libgcc_s.so.1 + * #6 0x00007fab276a34c6 in __GI___pthread_unwind at ./nptl/unwind.c:130 + * #7 0x00007fab2769bd3a in __do_cancel () at ../sysdeps/nptl/pthreadP.h:280 + * #8 __GI___pthread_exit (value=value@entry=0x0) at ./nptl/pthread_exit.c:36 + * #9 0x000000000052e567 in PyThread_exit_thread () at ../Python/thread_pthread.h:370 + * #10 0x00000000004d60b5 in take_gil at ../Python/ceval_gil.h:224 + * #11 0x00000000004d65f9 in PyEval_RestoreThread at ../Python/ceval.c:467 + * #12 0x000000000060cce3 in setipaddr at ../Modules/socketmodule.c:1203 + * #13 0x00000000006101cd in socket_gethostbyname + */ + + +/* The compiler used for Python 2.7 on Windows doesn't include + either stdint.h or cstdint.h. Nor does it understand nullptr or have + std::shared_ptr. = delete, etc Sigh. */ +#if defined(_MSC_VER) && _MSC_VER <= 1500 +typedef unsigned long long uint64_t; +typedef signed long long int64_t; +typedef unsigned int uint32_t; +// C++ defines NULL to be 0, which is ambiguous +// with an integer in certain cases, and won't autoconvert to a +// pointer in other cases. +#define nullptr NULL +#define G_HAS_METHOD_DELETE 0 +// Use G_EXPLICIT_OP as the prefix for operator methods +// that should be explicit. Old MSVC doesn't support explicit operator +// methods. +#define G_EXPLICIT_OP +#define G_NOEXCEPT throw() +// This version doesn't support "objects with internal linkage" +// in non-type template arguments. Translation: function pointer +// template arguments cannot be for static functions. +#define G_FP_TMPL_STATIC +#else +// Newer, reasonable compilers implementing C++11 or so. +#include +#define G_HAS_METHOD_DELETE 1 +#define G_EXPLICIT_OP explicit +#define G_NOEXCEPT noexcept +# if defined(__clang__) +# define G_FP_TMPL_STATIC static +# else +// GCC has no problem allowing static function pointers, but emits +// tons of warnings about "whose type uses the anonymous namespace [-Wsubobject-linkage]" +# define G_FP_TMPL_STATIC +# endif + +#endif + +#if G_HAS_METHOD_DELETE == 1 +# define G_NO_COPIES_OF_CLS(Cls) private: \ + Cls(const Cls& other) = delete; \ + Cls& operator=(const Cls& other) = delete + +# define G_NO_ASSIGNMENT_OF_CLS(Cls) private: \ + Cls& operator=(const Cls& other) = delete + +# define G_NO_COPY_CONSTRUCTOR_OF_CLS(Cls) private: \ + Cls(const Cls& other) = delete; +#else +# define G_NO_COPIES_OF_CLS(Cls) private: \ + Cls(const Cls& other); \ + Cls& operator=(const Cls& other) + +# define G_NO_ASSIGNMENT_OF_CLS(Cls) private: \ + Cls& operator=(const Cls& other) + +# define G_NO_COPY_CONSTRUCTOR_OF_CLS(Cls) private: \ + Cls(const Cls& other); +#endif + +// CAUTION: MSVC is stupidly picky: +// +// "The compiler ignores, without warning, any __declspec keywords +// placed after * or & and in front of the variable identifier in a +// declaration." +// (https://docs.microsoft.com/en-us/cpp/cpp/declspec?view=msvc-160) +// +// So pointer return types must be handled differently (because of the +// trailing *), or you get inscrutable compiler warnings like "error +// C2059: syntax error: ''" + +#if defined(__GNUC__) || defined(__clang__) +/* We used to check for GCC 4+ or 3.4+, but those compilers are + laughably out of date. Just assume they support it. */ +# define GREENLET_NOINLINE_SUPPORTED +# define GREENLET_NOINLINE(name) __attribute__((noinline)) name +# define GREENLET_NOINLINE_P(rtype, name) rtype __attribute__((noinline)) name +# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) +#elif defined(_MSC_VER) +/* We used to check for && (_MSC_VER >= 1300) but that's also out of date. */ +# define GREENLET_NOINLINE_SUPPORTED +# define GREENLET_NOINLINE(name) __declspec(noinline) name +# define GREENLET_NOINLINE_P(rtype, name) __declspec(noinline) rtype name +# define UNUSED(x) UNUSED_ ## x +#endif + +#if defined(_MSC_VER) +# define G_NOEXCEPT_WIN32 G_NOEXCEPT +#else +# define G_NOEXCEPT_WIN32 +#endif + + +#endif diff --git a/.venv/Lib/site-packages/greenlet/greenlet_cpython_compat.hpp b/.venv/Lib/site-packages/greenlet/greenlet_cpython_compat.hpp new file mode 100644 index 000000000..3fd13ac25 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/greenlet_cpython_compat.hpp @@ -0,0 +1,165 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +#ifndef GREENLET_CPYTHON_COMPAT_H +#define GREENLET_CPYTHON_COMPAT_H + +/** + * Helpers for compatibility with multiple versions of CPython. + */ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" + +// These enable writing template functions or classes specialized +// based on the Python version. Write both versions of the function, +// one with the WHEN version, one with the WHEN_NOT version. +// Instantiate the template using the G_IS_PY37 macro. +struct GREENLET_WHEN_PY37 +{ + typedef GREENLET_WHEN_PY37* Yes; + // We really just want an alias, `using Yes = IsIt`, + // but old MSVC for Py27 doesn't support that. + typedef GREENLET_WHEN_PY37* IsIt; +}; + +struct GREENLET_WHEN_NOT_PY37 +{ + typedef GREENLET_WHEN_NOT_PY37* No; + typedef GREENLET_WHEN_NOT_PY37* IsIt; +}; + + +#if PY_VERSION_HEX >= 0x030700A3 +# define GREENLET_PY37 1 +typedef GREENLET_WHEN_PY37 G_IS_PY37; +#else +# define GREENLET_PY37 0 +typedef GREENLET_WHEN_NOT_PY37 G_IS_PY37; +#endif + + +#if PY_VERSION_HEX >= 0x30A00B1 +/* +Python 3.10 beta 1 changed tstate->use_tracing to a nested cframe member. +See https://github.com/python/cpython/pull/25276 +We have to save and restore this as well. +*/ +# define GREENLET_USE_CFRAME 1 +#else +# define GREENLET_USE_CFRAME 0 +#endif + +#if PY_VERSION_HEX >= 0x30B00A4 +/* +Greenlet won't compile on anything older than Python 3.11 alpha 4 (see +https://bugs.python.org/issue46090). Summary of breaking internal changes: +- Python 3.11 alpha 1 changed how frame objects are represented internally. + - https://github.com/python/cpython/pull/30122 +- Python 3.11 alpha 3 changed how recursion limits are stored. + - https://github.com/python/cpython/pull/29524 +- Python 3.11 alpha 4 changed how exception state is stored. It also includes a + change to help greenlet save and restore the interpreter frame "data stack". + - https://github.com/python/cpython/pull/30122 + - https://github.com/python/cpython/pull/30234 +*/ +# define GREENLET_PY311 1 +#else +# define GREENLET_PY311 0 +#endif + +#ifndef Py_SET_REFCNT +/* Py_REFCNT and Py_SIZE macros are converted to functions +https://bugs.python.org/issue39573 */ +# define Py_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) +#endif + +#ifndef _Py_DEC_REFTOTAL +/* _Py_DEC_REFTOTAL macro has been removed from Python 3.9 by: + https://github.com/python/cpython/commit/49932fec62c616ec88da52642339d83ae719e924 +*/ +# ifdef Py_REF_DEBUG +# define _Py_DEC_REFTOTAL _Py_RefTotal-- +# else +# define _Py_DEC_REFTOTAL +# endif +#endif +// Define these flags like Cython does if we're on an old version. +#ifndef Py_TPFLAGS_CHECKTYPES + #define Py_TPFLAGS_CHECKTYPES 0 +#endif +#ifndef Py_TPFLAGS_HAVE_INDEX + #define Py_TPFLAGS_HAVE_INDEX 0 +#endif +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER + #define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif +#ifndef Py_TPFLAGS_HAVE_FINALIZE + #define Py_TPFLAGS_HAVE_FINALIZE 0 +#endif +#ifndef Py_TPFLAGS_HAVE_VERSION_TAG + #define Py_TPFLAGS_HAVE_VERSION_TAG 0 +#endif + +#define G_TPFLAGS_DEFAULT Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_VERSION_TAG | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_HAVE_NEWBUFFER | Py_TPFLAGS_HAVE_GC + +#if PY_MAJOR_VERSION >= 3 +# define GNative_FromFormat PyUnicode_FromFormat +#else +# define GNative_FromFormat PyString_FromFormat +#endif + +#if PY_MAJOR_VERSION >= 3 +# define Greenlet_Intern PyUnicode_InternFromString +#else +# define Greenlet_Intern PyString_InternFromString +#endif + +#if PY_VERSION_HEX < 0x03090000 +// The official version only became available in 3.9 +# define PyObject_GC_IsTracked(o) _PyObject_GC_IS_TRACKED(o) +#endif + +#if PY_MAJOR_VERSION < 3 +struct PyModuleDef { + int unused; + const char* const m_name; + const char* m_doc; + Py_ssize_t m_size; + PyMethodDef* m_methods; + // Then several more fields we're not currently using. +}; +#define PyModuleDef_HEAD_INIT 1 +PyObject* PyModule_Create(PyModuleDef* m) +{ + return Py_InitModule(m->m_name, m->m_methods); +} +#endif + +// bpo-43760 added PyThreadState_EnterTracing() to Python 3.11.0a2 +#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION) +static inline void PyThreadState_EnterTracing(PyThreadState *tstate) +{ + tstate->tracing++; +#if PY_VERSION_HEX >= 0x030A00A1 + tstate->cframe->use_tracing = 0; +#else + tstate->use_tracing = 0; +#endif +} +#endif + +// bpo-43760 added PyThreadState_LeaveTracing() to Python 3.11.0a2 +#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION) +static inline void PyThreadState_LeaveTracing(PyThreadState *tstate) +{ + tstate->tracing--; + int use_tracing = (tstate->c_tracefunc != NULL + || tstate->c_profilefunc != NULL); +#if PY_VERSION_HEX >= 0x030A00A1 + tstate->cframe->use_tracing = use_tracing; +#else + tstate->use_tracing = use_tracing; +#endif +} +#endif + +#endif /* GREENLET_CPYTHON_COMPAT_H */ diff --git a/.venv/Lib/site-packages/greenlet/greenlet_exceptions.hpp b/.venv/Lib/site-packages/greenlet/greenlet_exceptions.hpp new file mode 100644 index 000000000..697df0026 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/greenlet_exceptions.hpp @@ -0,0 +1,106 @@ +#ifndef GREENLET_EXCEPTIONS_HPP +#define GREENLET_EXCEPTIONS_HPP + +#define PY_SSIZE_T_CLEAN +#include +#include +#include + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunused-function" +#endif + +namespace greenlet { + + class PyErrOccurred : public std::runtime_error + { + public: + PyErrOccurred() : std::runtime_error("") + { + assert(PyErr_Occurred()); + } + + PyErrOccurred(PyObject* exc_kind, const char* const msg) + : std::runtime_error(msg) + { + PyErr_SetString(exc_kind, msg); + } + PyErrOccurred(PyObject* exc_kind, const std::string msg) + : std::runtime_error(msg) + { + // This copies the c_str, so we don't have any lifetime + // issues to worry about. + PyErr_SetString(exc_kind, msg.c_str()); + } + }; + + class TypeError : public PyErrOccurred + { + public: + TypeError(const char* const what) + : PyErrOccurred(PyExc_TypeError, what) + { + } + TypeError(const std::string what) + : PyErrOccurred(PyExc_TypeError, what) + { + } + }; + + class ValueError : public PyErrOccurred + { + public: + ValueError(const char* const what) + : PyErrOccurred(PyExc_ValueError, what) + { + } + }; + + class AttributeError : public PyErrOccurred + { + public: + AttributeError(const char* const what) + : PyErrOccurred(PyExc_AttributeError, what) + { + } + }; + + /** + * Calls `Py_FatalError` when constructed, so you can't actually + * throw this. It just makes static analysis easier. + */ + class PyFatalError : public std::runtime_error + { + public: + PyFatalError(const char* const msg) + : std::runtime_error(msg) + { + Py_FatalError(msg); + } + }; + + static inline PyObject* + Require(PyObject* p) + { + if (!p) { + throw PyErrOccurred(); + } + return p; + }; + + static inline void + Require(const int retval) + { + if (retval < 0) { + throw PyErrOccurred(); + } + }; + + +}; +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + +#endif diff --git a/.venv/Lib/site-packages/greenlet/greenlet_greenlet.hpp b/.venv/Lib/site-packages/greenlet/greenlet_greenlet.hpp new file mode 100644 index 000000000..cc02c5c5a --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/greenlet_greenlet.hpp @@ -0,0 +1,1272 @@ +#ifndef GREENLET_GREENLET_HPP +#define GREENLET_GREENLET_HPP +/* + * Declarations of the core data structures. +*/ + +#define PY_SSIZE_T_CLEAN +#include + +#include "greenlet_compiler_compat.hpp" +#include "greenlet_refs.hpp" +#include "greenlet_cpython_compat.hpp" +#include "greenlet_allocator.hpp" + +using greenlet::refs::OwnedObject; +using greenlet::refs::OwnedGreenlet; +using greenlet::refs::OwnedMainGreenlet; +using greenlet::refs::BorrowedGreenlet; + +#if PY_VERSION_HEX < 0x30B00A6 +# define _PyCFrame CFrame +# define _PyInterpreterFrame _interpreter_frame +#endif + +// XXX: TODO: Work to remove all virtual functions +// for speed of calling and size of objects (no vtable). +// One pattern is the Curiously Recurring Template +namespace greenlet +{ + class ExceptionState + { + private: + G_NO_COPIES_OF_CLS(ExceptionState); + +#if PY_VERSION_HEX >= 0x030700A3 + // Even though these are borrowed objects, we actually own + // them, when they're not null. + // XXX: Express that in the API. + private: + _PyErr_StackItem* exc_info; + _PyErr_StackItem exc_state; +#else + OwnedObject exc_value; +#if !GREENLET_PY311 + OwnedObject exc_type; + OwnedObject exc_traceback; +#endif +#endif + public: + ExceptionState(); + void operator<<(const PyThreadState *const tstate) G_NOEXCEPT; + void operator>>(PyThreadState* tstate) G_NOEXCEPT; + void clear() G_NOEXCEPT; + + int tp_traverse(visitproc visit, void* arg) G_NOEXCEPT; + void tp_clear() G_NOEXCEPT; + }; + + template + void operator<<(const PyThreadState *const tstate, T& exc); + + template + class PythonStateContext + {}; + + template<> + class PythonStateContext + { + protected: + greenlet::refs::OwnedContext _context; + public: + inline const greenlet::refs::OwnedContext& context() const + { + return this->_context; + } + inline greenlet::refs::OwnedContext& context() + { + return this->_context; + } + + inline void tp_clear() + { + this->_context.CLEAR(); + } + + template + inline static PyObject* context(T* tstate) + { + return tstate->context; + } + + template + inline static void context(T* tstate, PyObject* new_context) + { + tstate->context = new_context; + tstate->context_ver++; + } + }; + + + template<> + class PythonStateContext + { + public: + inline const greenlet::refs::OwnedContext& context() const + { + throw AttributeError("no context"); + } + + inline greenlet::refs::OwnedContext& context() + { + throw AttributeError("no context"); + } + + inline void tp_clear(){}; + + template + inline static PyObject* context(T* UNUSED(tstate)) + { + throw PyFatalError("This should never be called."); + } + + template + inline static void context(T* UNUSED(tstate), PyObject* UNUSED(new_context)) + { + throw PyFatalError("This should never be called."); + } + }; + + class PythonState : public PythonStateContext + { + public: + typedef greenlet::refs::OwnedReference OwnedFrame; + private: + G_NO_COPIES_OF_CLS(PythonState); + // We own this if we're suspended (although currently we don't + // tp_traverse into it; that's a TODO). If we're running, it's + // empty. If we get deallocated and *still* have a frame, it + // won't be reachable from the place that normally decref's + // it, so we need to do it (hence owning it). + OwnedFrame _top_frame; +#if GREENLET_USE_CFRAME + _PyCFrame* cframe; + int use_tracing; +#endif + int recursion_depth; + int trash_delete_nesting; +#if GREENLET_PY311 + _PyInterpreterFrame* current_frame; + _PyStackChunk* datastack_chunk; + PyObject** datastack_top; + PyObject** datastack_limit; +#endif + + public: + PythonState(); + // You can use this for testing whether we have a frame + // or not. It returns const so they can't modify it. + const OwnedFrame& top_frame() const G_NOEXCEPT; + + + void operator<<(const PyThreadState *const tstate) G_NOEXCEPT; + void operator>>(PyThreadState* tstate) G_NOEXCEPT; + void clear() G_NOEXCEPT; + + int tp_traverse(visitproc visit, void* arg, bool visit_top_frame) G_NOEXCEPT; + void tp_clear(bool own_top_frame) G_NOEXCEPT; + void set_initial_state(const PyThreadState* const tstate) G_NOEXCEPT; +#if GREENLET_USE_CFRAME + void set_new_cframe(_PyCFrame& frame) G_NOEXCEPT; +#endif + void will_switch_from(PyThreadState *const origin_tstate) G_NOEXCEPT; + void did_finish(PyThreadState* tstate) G_NOEXCEPT; + }; + + class StackState + { + // By having only plain C (POD) members, no virtual functions + // or bases, we get a trivial assignment operator generated + // for us. However, that's not safe since we do manage memory. + // So we declare an assignment operator that only works if we + // don't have any memory allocated. (We don't use + // std::shared_ptr for reference counting just to keep this + // object small) + private: + char* _stack_start; + char* stack_stop; + char* stack_copy; + intptr_t _stack_saved; + StackState* stack_prev; + inline int copy_stack_to_heap_up_to(const char* const stop) G_NOEXCEPT; + inline void free_stack_copy() G_NOEXCEPT; + + public: + /** + * Creates a started, but inactive, state, using *current* + * as the previous. + */ + StackState(void* mark, StackState& current); + /** + * Creates an inactive, unstarted, state. + */ + StackState(); + ~StackState(); + StackState(const StackState& other); + StackState& operator=(const StackState& other); + inline void copy_heap_to_stack(const StackState& current) G_NOEXCEPT; + inline int copy_stack_to_heap(char* const stackref, const StackState& current) G_NOEXCEPT; + inline bool started() const G_NOEXCEPT; + inline bool main() const G_NOEXCEPT; + inline bool active() const G_NOEXCEPT; + inline void set_active() G_NOEXCEPT; + inline void set_inactive() G_NOEXCEPT; + inline intptr_t stack_saved() const G_NOEXCEPT; + inline char* stack_start() const G_NOEXCEPT; + static inline StackState make_main() G_NOEXCEPT; +#ifdef GREENLET_USE_STDIO + friend std::ostream& operator<<(std::ostream& os, const StackState& s); +#endif + }; +#ifdef GREENLET_USE_STDIO + std::ostream& operator<<(std::ostream& os, const StackState& s); +#endif + + class SwitchingArgs + { + private: + G_NO_ASSIGNMENT_OF_CLS(SwitchingArgs); + // If args and kwargs are both false (NULL), this is a *throw*, not a + // switch. PyErr_... must have been called already. + OwnedObject _args; + OwnedObject _kwargs; + public: + + SwitchingArgs() + {} + + SwitchingArgs(const OwnedObject& args, const OwnedObject& kwargs) + : _args(args), + _kwargs(kwargs) + {} + + SwitchingArgs(const SwitchingArgs& other) + : _args(other._args), + _kwargs(other._kwargs) + {} + + OwnedObject& args() + { + return this->_args; + } + + OwnedObject& kwargs() + { + return this->_kwargs; + } + + /** + * Moves ownership from the argument to this object. + */ + SwitchingArgs& operator<<=(SwitchingArgs& other) + { + if (this != &other) { + this->_args = other._args; + this->_kwargs = other._kwargs; + other.CLEAR(); + } + return *this; + } + + /** + * Acquires ownership of the argument (consumes the reference). + */ + SwitchingArgs& operator<<=(PyObject* args) + { + this->_args = OwnedObject::consuming(args); + this->_kwargs.CLEAR(); + return *this; + } + + /** + * Acquires ownership of the argument. + * + * Sets the args to be the given value; clears the kwargs. + */ + SwitchingArgs& operator<<=(OwnedObject& args) + { + assert(&args != &this->_args); + this->_args = args; + this->_kwargs.CLEAR(); + args.CLEAR(); + + return *this; + } + + G_EXPLICIT_OP operator bool() const G_NOEXCEPT + { + return this->_args || this->_kwargs; + } + + inline void CLEAR() + { + this->_args.CLEAR(); + this->_kwargs.CLEAR(); + } + }; + + class ThreadState; + + class UserGreenlet; + class MainGreenlet; + + class Greenlet + { + private: + G_NO_COPIES_OF_CLS(Greenlet); + private: + // XXX: Work to remove these. + friend class ThreadState; + friend class UserGreenlet; + friend class MainGreenlet; + protected: + ExceptionState exception_state; + SwitchingArgs switch_args; + StackState stack_state; + PythonState python_state; + Greenlet(PyGreenlet* p, const StackState& initial_state); + public: + Greenlet(PyGreenlet* p); + virtual ~Greenlet(); + + template // maybe we can use a value here? + const OwnedObject context(const typename IsPy37::IsIt=nullptr) const; + + template + inline void context(refs::BorrowedObject new_context, typename IsPy37::IsIt=nullptr); + + inline SwitchingArgs& args() + { + return this->switch_args; + } + + virtual const refs::BorrowedMainGreenlet main_greenlet() const = 0; + + inline intptr_t stack_saved() const G_NOEXCEPT + { + return this->stack_state.stack_saved(); + } + + // This is used by the macro SLP_SAVE_STATE to compute the + // difference in stack sizes. It might be nice to handle the + // computation ourself, but the type of the result + // varies by platform, so doing it in the macro is the + // simplest way. + inline const char* stack_start() const G_NOEXCEPT + { + return this->stack_state.stack_start(); + } + + virtual OwnedObject throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state); + virtual OwnedObject g_switch() = 0; + /** + * Force the greenlet to appear dead. Used when it's not + * possible to throw an exception into a greenlet anymore. + * + * This losses access to the thread state and the main greenlet. + */ + virtual void murder_in_place(); + + /** + * Called when somebody notices we were running in a dead + * thread to allow cleaning up resources (because we can't + * raise GreenletExit into it anymore). + * This is very similar to ``murder_in_place()``, except that + * it DOES NOT lose the main greenlet or thread state. + */ + inline void deactivate_and_free(); + + + // Called when some thread wants to deallocate a greenlet + // object. + // The thread may or may not be the same thread the greenlet + // was running in. + // The thread state will be null if the thread the greenlet + // was running in was known to have exited. + void deallocing_greenlet_in_thread(const ThreadState* current_state); + + // TODO: Figure out how to make these non-public. + inline void slp_restore_state() G_NOEXCEPT; + inline int slp_save_state(char *const stackref) G_NOEXCEPT; + + inline bool is_currently_running_in_some_thread() const; + virtual bool belongs_to_thread(const ThreadState* state) const; + + inline bool started() const + { + return this->stack_state.started(); + } + inline bool active() const + { + return this->stack_state.active(); + } + inline bool main() const + { + return this->stack_state.main(); + } + virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const = 0; + + virtual const OwnedGreenlet parent() const = 0; + virtual void parent(const refs::BorrowedObject new_parent) = 0; + + inline const PythonState::OwnedFrame& top_frame() + { + return this->python_state.top_frame(); + } + + virtual const OwnedObject& run() const = 0; + virtual void run(const refs::BorrowedObject nrun) = 0; + + + virtual int tp_traverse(visitproc visit, void* arg); + virtual int tp_clear(); + + + // Return the thread state that the greenlet is running in, or + // null if the greenlet is not running or the thread is known + // to have exited. + virtual ThreadState* thread_state() const G_NOEXCEPT = 0; + + // Return true if the greenlet is known to have been running + // (active) in a thread that has now exited. + virtual bool was_running_in_dead_thread() const G_NOEXCEPT = 0; + + // Return a borrowed greenlet that is the Python object + // this object represents. + virtual BorrowedGreenlet self() const G_NOEXCEPT = 0; + + protected: + inline void release_args(); + + // The functions that must not be inlined are declared virtual. + // We also mark them as protected, not private, so that the + // compiler is forced to call them through a function pointer. + // (A sufficiently smart compiler could directly call a private + // virtual function since it can never be overridden in a + // subclass). + + // Also TODO: Switch away from integer error codes and to enums, + // or throw exceptions when possible. + struct switchstack_result_t + { + int status; + Greenlet* the_state_that_switched; + OwnedGreenlet origin_greenlet; + + switchstack_result_t() + : status(0), + the_state_that_switched(nullptr) + {} + + switchstack_result_t(int err) + : status(err), + the_state_that_switched(nullptr) + {} + + switchstack_result_t(int err, Greenlet* state, OwnedGreenlet& origin) + : status(err), + the_state_that_switched(state), + origin_greenlet(origin) + { + } + + switchstack_result_t(int err, Greenlet* state, const BorrowedGreenlet& origin) + : status(err), + the_state_that_switched(state), + origin_greenlet(origin) + { + } + + switchstack_result_t& operator=(const switchstack_result_t& other) + { + this->status = other.status; + this->the_state_that_switched = other.the_state_that_switched; + this->origin_greenlet = other.origin_greenlet; + return *this; + } + }; + + // Returns the previous greenlet we just switched away from. + virtual OwnedGreenlet g_switchstack_success() G_NOEXCEPT; + + + // Check the preconditions for switching to this greenlet; if they + // aren't met, throws PyErrOccurred. Most callers will want to + // catch this and clear the arguments + inline void check_switch_allowed() const; + class GreenletStartedWhileInPython : public std::runtime_error + { + public: + GreenletStartedWhileInPython() : std::runtime_error("") + {} + }; + + protected: + + + /** + Perform a stack switch into this greenlet. + + This temporarily sets the global variable + ``switching_thread_state`` to this greenlet; as soon as the + call to ``slp_switch`` completes, this is reset to NULL. + Consequently, this depends on the GIL. + + TODO: Adopt the stackman model and pass ``slp_switch`` a + callback function and context pointer; this eliminates the + need for global variables altogether. + + Because the stack switch happens in this function, this + function can't use its own stack (local) variables, set + before the switch, and then accessed after the switch. + + Further, you con't even access ``g_thread_state_global`` + before and after the switch from the global variable. + Because it is thread local some compilers cache it in a + register/on the stack, notably new versions of MSVC; this + breaks with strange crashes sometime later, because writing + to anything in ``g_thread_state_global`` after the switch + is actually writing to random memory. For this reason, we + call a non-inlined function to finish the operation. (XXX: + The ``/GT`` MSVC compiler argument probably fixes that.) + + It is very important that stack switch is 'atomic', i.e. no + calls into other Python code allowed (except very few that + are safe), because global variables are very fragile. (This + should no longer be the case with thread-local variables.) + + */ + switchstack_result_t g_switchstack(void); + private: + OwnedObject g_switch_finish(const switchstack_result_t& err); + + }; + + class UserGreenlet : public Greenlet + { + private: + static greenlet::PythonAllocator allocator; + BorrowedGreenlet _self; + OwnedMainGreenlet _main_greenlet; + OwnedObject _run_callable; + OwnedGreenlet _parent; + public: + static void* operator new(size_t UNUSED(count)); + static void operator delete(void* ptr); + + UserGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent); + virtual ~UserGreenlet(); + + virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const; + virtual bool was_running_in_dead_thread() const G_NOEXCEPT; + virtual ThreadState* thread_state() const G_NOEXCEPT; + virtual OwnedObject g_switch(); + virtual const OwnedObject& run() const + { + if (this->started() || !this->_run_callable) { + throw AttributeError("run"); + } + return this->_run_callable; + } + virtual void run(const refs::BorrowedObject nrun); + + virtual const OwnedGreenlet parent() const; + virtual void parent(const refs::BorrowedObject new_parent); + + virtual const refs::BorrowedMainGreenlet main_greenlet() const; + + virtual BorrowedGreenlet self() const G_NOEXCEPT; + virtual void murder_in_place(); + virtual bool belongs_to_thread(const ThreadState* state) const; + virtual int tp_traverse(visitproc visit, void* arg); + virtual int tp_clear(); + class ParentIsCurrentGuard + { + private: + OwnedGreenlet oldparent; + UserGreenlet* greenlet; + G_NO_COPIES_OF_CLS(ParentIsCurrentGuard); + public: + ParentIsCurrentGuard(UserGreenlet* p, const ThreadState& thread_state); + ~ParentIsCurrentGuard(); + }; + virtual OwnedObject throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state); + protected: + virtual switchstack_result_t g_initialstub(void* mark); + private: + void inner_bootstrap(OwnedGreenlet& origin_greenlet, OwnedObject& run) G_NOEXCEPT_WIN32; + }; + + class MainGreenlet : public Greenlet + { + private: + static greenlet::PythonAllocator allocator; + refs::BorrowedMainGreenlet _self; + ThreadState* _thread_state; + G_NO_COPIES_OF_CLS(MainGreenlet); + public: + static void* operator new(size_t UNUSED(count)); + static void operator delete(void* ptr); + + MainGreenlet(refs::BorrowedMainGreenlet::PyType*, ThreadState*); + virtual ~MainGreenlet(); + + + virtual const OwnedObject& run() const; + virtual void run(const refs::BorrowedObject nrun); + + virtual const OwnedGreenlet parent() const; + virtual void parent(const refs::BorrowedObject new_parent); + + virtual const refs::BorrowedMainGreenlet main_greenlet() const; + + virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const; + virtual bool was_running_in_dead_thread() const G_NOEXCEPT; + virtual ThreadState* thread_state() const G_NOEXCEPT; + void thread_state(ThreadState*) G_NOEXCEPT; + virtual OwnedObject g_switch(); + virtual BorrowedGreenlet self() const G_NOEXCEPT; + virtual int tp_traverse(visitproc visit, void* arg); + }; + +}; + +template +void greenlet::operator<<(const PyThreadState *const lhs, T& rhs) +{ + rhs.operator<<(lhs); +} + +using greenlet::ExceptionState; + +ExceptionState::ExceptionState() +{ + this->clear(); +} + +#if PY_VERSION_HEX >= 0x030700A3 +// ******** Python 3.7 and above ********* +void ExceptionState::operator<<(const PyThreadState *const tstate) G_NOEXCEPT +{ + this->exc_info = tstate->exc_info; + this->exc_state = tstate->exc_state; +} + +void ExceptionState::operator>>(PyThreadState *const tstate) G_NOEXCEPT +{ + tstate->exc_state = this->exc_state; + tstate->exc_info = + this->exc_info ? this->exc_info : &tstate->exc_state; + this->clear(); +} + +void ExceptionState::clear() G_NOEXCEPT +{ + this->exc_info = nullptr; + this->exc_state.exc_value = nullptr; +#if !GREENLET_PY311 + this->exc_state.exc_type = nullptr; + this->exc_state.exc_traceback = nullptr; +#endif + this->exc_state.previous_item = nullptr; +} + +int ExceptionState::tp_traverse(visitproc visit, void* arg) G_NOEXCEPT +{ + Py_VISIT(this->exc_state.exc_value); +#if !GREENLET_PY311 + Py_VISIT(this->exc_state.exc_type); + Py_VISIT(this->exc_state.exc_traceback); +#endif + return 0; +} + +void ExceptionState::tp_clear() G_NOEXCEPT +{ + Py_CLEAR(this->exc_state.exc_value); +#if !GREENLET_PY311 + Py_CLEAR(this->exc_state.exc_type); + Py_CLEAR(this->exc_state.exc_traceback); +#endif +} +#else +// ********** Python 3.6 and below ******** +void ExceptionState::operator<<(const PyThreadState *const tstate) G_NOEXCEPT +{ + this->exc_value.steal(tstate->exc_value); +#if !GREENLET_PY311 + this->exc_type.steal(tstate->exc_type); + this->exc_traceback.steal(tstate->exc_traceback); +#endif +} + +void ExceptionState::operator>>(PyThreadState *const tstate) G_NOEXCEPT +{ + tstate->exc_value <<= this->exc_value; +#if !GREENLET_PY311 + tstate->exc_type <<= this->exc_type; + tstate->exc_traceback <<= this->exc_traceback; +#endif + this->clear(); +} + +void ExceptionState::clear() G_NOEXCEPT +{ + this->exc_value = nullptr; +#if !GREENLET_PY311 + this->exc_type = nullptr; + this->exc_traceback = nullptr; +#endif +} + +int ExceptionState::tp_traverse(visitproc visit, void* arg) G_NOEXCEPT +{ + Py_VISIT(this->exc_value.borrow()); +#if !GREENLET_PY311 + Py_VISIT(this->exc_type.borrow()); + Py_VISIT(this->exc_traceback.borrow()); +#endif + return 0; +} + +void ExceptionState::tp_clear() G_NOEXCEPT +{ + this->exc_value.CLEAR(); +#if !GREENLET_PY311 + this->exc_type.CLEAR(); + this->exc_traceback.CLEAR(); +#endif +} +#endif + + +using greenlet::PythonState; + +PythonState::PythonState() + : _top_frame() +#if GREENLET_USE_CFRAME + ,cframe(nullptr) + ,use_tracing(0) +#endif + ,recursion_depth(0) + ,trash_delete_nesting(0) +#if GREENLET_PY311 + ,current_frame(nullptr) + ,datastack_chunk(nullptr) + ,datastack_top(nullptr) + ,datastack_limit(nullptr) +#endif +{ +#if GREENLET_USE_CFRAME + /* + The PyThreadState->cframe pointer usually points to memory on + the stack, alloceted in a call into PyEval_EvalFrameDefault. + + Initially, before any evaluation begins, it points to the + initial PyThreadState object's ``root_cframe`` object, which is + statically allocated for the lifetime of the thread. + + A greenlet can last for longer than a call to + PyEval_EvalFrameDefault, so we can't set its ``cframe`` pointer + to be the current ``PyThreadState->cframe``; nor could we use + one from the greenlet parent for the same reason. Yet a further + no: we can't allocate one scoped to the greenlet and then + destroy it when the greenlet is deallocated, because inside the + interpreter the _PyCFrame objects form a linked list, and that too + can result in accessing memory beyond its dynamic lifetime (if + the greenlet doesn't actually finish before it dies, its entry + could still be in the list). + + Using the ``root_cframe`` is problematic, though, because its + members are never modified by the interpreter and are set to 0, + meaning that its ``use_tracing`` flag is never updated. We don't + want to modify that value in the ``root_cframe`` ourself: it + *shouldn't* matter much because we should probably never get + back to the point where that's the only cframe on the stack; + even if it did matter, the major consequence of an incorrect + value for ``use_tracing`` is that if its true the interpreter + does some extra work --- however, it's just good code hygiene. + + Our solution: before a greenlet runs, after its initial + creation, it uses the ``root_cframe`` just to have something to + put there. However, once the greenlet is actually switched to + for the first time, ``g_initialstub`` (which doesn't actually + "return" while the greenlet is running) stores a new _PyCFrame on + its local stack, and copies the appropriate values from the + currently running _PyCFrame; this is then made the _PyCFrame for the + newly-minted greenlet. ``g_initialstub`` then proceeds to call + ``glet.run()``, which results in ``PyEval_...`` adding the + _PyCFrame to the list. Switches continue as normal. Finally, when + the greenlet finishes, the call to ``glet.run()`` returns and + the _PyCFrame is taken out of the linked list and the stack value + is now unused and free to expire. + + XXX: I think we can do better. If we're deallocing in the same + thread, can't we traverse the list and unlink our frame? + Can we just keep a reference to the thread state in case we + dealloc in another thread? (Is that even possible if we're still + running and haven't returned from g_initialstub?) + */ + this->cframe = &PyThreadState_GET()->root_cframe; +#endif +} + +void PythonState::operator<<(const PyThreadState *const tstate) G_NOEXCEPT +{ +#if GREENLET_PY37 + this->_context.steal(tstate->context); +#endif +#if GREENLET_USE_CFRAME + /* + IMPORTANT: ``cframe`` is a pointer into the STACK. Thus, because + the call to ``slp_switch()`` changes the contents of the stack, + you cannot read from ``ts_current->cframe`` after that call and + necessarily get the same values you get from reading it here. + Anything you need to restore from now to then must be saved in a + global/threadlocal variable (because we can't use stack + variables here either). For things that need to persist across + the switch, use `will_switch_from`. + */ + this->cframe = tstate->cframe; + this->use_tracing = tstate->cframe->use_tracing; +#endif +#if GREENLET_PY311 + this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; + this->current_frame = tstate->cframe->current_frame; + this->datastack_chunk = tstate->datastack_chunk; + this->datastack_top = tstate->datastack_top; + this->datastack_limit = tstate->datastack_limit; + PyFrameObject *frame = PyThreadState_GetFrame((PyThreadState *)tstate); + Py_XDECREF(frame); // PyThreadState_GetFrame gives us a new reference. + this->_top_frame.steal(frame); +#else + this->recursion_depth = tstate->recursion_depth; + this->_top_frame.steal(tstate->frame); +#endif + + // All versions of Python. + this->trash_delete_nesting = tstate->trash_delete_nesting; +} + +void PythonState::operator>>(PyThreadState *const tstate) G_NOEXCEPT +{ +#if GREENLET_PY37 + tstate->context = this->_context.relinquish_ownership(); + /* Incrementing this value invalidates the contextvars cache, + which would otherwise remain valid across switches */ + tstate->context_ver++; +#endif +#if GREENLET_USE_CFRAME + tstate->cframe = this->cframe; + /* + If we were tracing, we need to keep tracing. + There should never be the possibility of hitting the + root_cframe here. See note above about why we can't + just copy this from ``origin->cframe->use_tracing``. + */ + tstate->cframe->use_tracing = this->use_tracing; +#endif +#if GREENLET_PY311 + tstate->recursion_remaining = tstate->recursion_limit - this->recursion_depth; + tstate->cframe->current_frame = this->current_frame; + tstate->datastack_chunk = this->datastack_chunk; + tstate->datastack_top = this->datastack_top; + tstate->datastack_limit = this->datastack_limit; + this->_top_frame.relinquish_ownership(); +#else + tstate->frame = this->_top_frame.relinquish_ownership(); + tstate->recursion_depth = this->recursion_depth; +#endif + // All versions of Python. + tstate->trash_delete_nesting = this->trash_delete_nesting; +} + +void PythonState::will_switch_from(PyThreadState *const origin_tstate) G_NOEXCEPT +{ +#if GREENLET_USE_CFRAME + // The weird thing is, we don't actually save this for an + // effect on the current greenlet, it's saved for an + // effect on the target greenlet. That is, we want + // continuity of this setting across the greenlet switch. + this->use_tracing = origin_tstate->cframe->use_tracing; +#endif +} + +void PythonState::set_initial_state(const PyThreadState* const tstate) G_NOEXCEPT +{ + this->_top_frame = nullptr; +#if GREENLET_PY311 + this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; +#else + this->recursion_depth = tstate->recursion_depth; +#endif +} +// TODO: Better state management about when we own the top frame. +int PythonState::tp_traverse(visitproc visit, void* arg, bool own_top_frame) G_NOEXCEPT +{ +#if GREENLET_PY37 + Py_VISIT(this->_context.borrow()); +#endif + if (own_top_frame) { + Py_VISIT(this->_top_frame.borrow()); + } + return 0; +} + +void PythonState::tp_clear(bool own_top_frame) G_NOEXCEPT +{ + PythonStateContext::tp_clear(); + // If we get here owning a frame, + // we got dealloc'd without being finished. We may or may not be + // in the same thread. + if (own_top_frame) { + this->_top_frame.CLEAR(); + } +} + +#if GREENLET_USE_CFRAME +void PythonState::set_new_cframe(_PyCFrame& frame) G_NOEXCEPT +{ + frame = *PyThreadState_GET()->cframe; + /* Make the target greenlet refer to the stack value. */ + this->cframe = &frame; + /* + And restore the link to the previous frame so this one gets + unliked appropriately. + */ + this->cframe->previous = &PyThreadState_GET()->root_cframe; +} +#endif + +const PythonState::OwnedFrame& PythonState::top_frame() const G_NOEXCEPT +{ + return this->_top_frame; +} + +void PythonState::did_finish(PyThreadState* tstate) G_NOEXCEPT +{ +#if GREENLET_PY311 + // See https://github.com/gevent/gevent/issues/1924 and + // https://github.com/python-greenlet/greenlet/issues/328. In + // short, Python 3.11 allocates memory for frames as a sort of + // linked list that's kept as part of PyThreadState in the + // ``datastack_chunk`` member and friends. These are saved and + // restored as part of switching greenlets. + // + // When we initially switch to a greenlet, we set those to NULL. + // That causes the frame management code to treat this like a + // brand new thread and start a fresh list of chunks, beginning + // with a new "root" chunk. As we make calls in this greenlet, + // those chunks get added, and as calls return, they get popped. + // But the frame code (pystate.c) is careful to make sure that the + // root chunk never gets popped. + // + // Thus, when a greenlet exits for the last time, there will be at + // least a single root chunk that we must be responsible for + // deallocating. + // + // The complex part is that these chunks are allocated and freed + // using ``_PyObject_VirtualAlloc``/``Free``. Those aren't public + // functions, and they aren't exported for linking. It so happens + // that we know they are just thin wrappers around the Arena + // allocator, so we can use that directly to deallocate in a + // compatible way. + // + // CAUTION: Check this implementation detail on every major version. + // + // It might be nice to be able to do this in our destructor, but + // can we be sure that no one else is using that memory? Plus, as + // described below, our pointers may not even be valid anymore. As + // a special case, there is one time that we know we can do this, + // and that's from the destructor of the associated UserGreenlet + // (NOT main greenlet) + PyObjectArenaAllocator alloc; + _PyStackChunk* chunk = nullptr; + if (tstate) { + // We really did finish, we can never be switched to again. + chunk = tstate->datastack_chunk; + // Unfortunately, we can't do much sanity checking. Our + // this->datastack_chunk pointer is out of date (evaluation may + // have popped down through it already) so we can't verify that + // we deallocate it. I don't think we can even check datastack_top + // for the same reason. + + PyObject_GetArenaAllocator(&alloc); + tstate->datastack_chunk = nullptr; + tstate->datastack_limit = nullptr; + tstate->datastack_top = nullptr; + + } + else if (this->datastack_chunk) { + // The UserGreenlet (NOT the main greenlet!) is being deallocated. If we're + // still holding a stack chunk, it's garbage because we know + // we can never switch back to let cPython clean it up. + // Because the last time we got switched away from, and we + // haven't run since then, we know our chain is valid and can + // be dealloced. + chunk = this->datastack_chunk; + PyObject_GetArenaAllocator(&alloc); + } + + if (alloc.free && chunk) { + // In case the arena mechanism has been torn down already. + while (chunk) { + _PyStackChunk *prev = chunk->previous; + chunk->previous = nullptr; + alloc.free(alloc.ctx, chunk, chunk->size); + chunk = prev; + } + } + + this->datastack_chunk = nullptr; + this->datastack_limit = nullptr; + this->datastack_top = nullptr; +#endif +} + + + + +using greenlet::StackState; + +#ifdef GREENLET_USE_STDIO +#include +using std::cerr; +using std::endl; + +std::ostream& greenlet::operator<<(std::ostream& os, const StackState& s) +{ + os << "StackState(stack_start=" << (void*)s._stack_start + << ", stack_stop=" << (void*)s.stack_stop + << ", stack_copy=" << (void*)s.stack_copy + << ", stack_saved=" << s._stack_saved + << ", stack_prev=" << s.stack_prev + << ", addr=" << &s + << ")"; + return os; +} +#endif + +StackState::StackState(void* mark, StackState& current) + : _stack_start(nullptr), + stack_stop((char*)mark), + stack_copy(nullptr), + _stack_saved(0), + /* Skip a dying greenlet */ + stack_prev(current._stack_start + ? ¤t + : current.stack_prev) +{ +} + +StackState::StackState() + : _stack_start(nullptr), + stack_stop(nullptr), + stack_copy(nullptr), + _stack_saved(0), + stack_prev(nullptr) +{ +} + +StackState::StackState(const StackState& other) +// can't use a delegating constructor because of +// MSVC for Python 2.7 + : _stack_start(nullptr), + stack_stop(nullptr), + stack_copy(nullptr), + _stack_saved(0), + stack_prev(nullptr) +{ + this->operator=(other); +} + +StackState& StackState::operator=(const StackState& other) +{ + if (&other == this) { + return *this; + } + if (other._stack_saved) { + throw std::runtime_error("Refusing to steal memory."); + } + + //If we have memory allocated, dispose of it + this->free_stack_copy(); + + this->_stack_start = other._stack_start; + this->stack_stop = other.stack_stop; + this->stack_copy = other.stack_copy; + this->_stack_saved = other._stack_saved; + this->stack_prev = other.stack_prev; + return *this; +} + +inline void StackState::free_stack_copy() G_NOEXCEPT +{ + PyMem_Free(this->stack_copy); + this->stack_copy = nullptr; + this->_stack_saved = 0; +} + +inline void StackState::copy_heap_to_stack(const StackState& current) G_NOEXCEPT +{ + // cerr << "copy_heap_to_stack" << endl + // << "\tFrom : " << *this << endl + // << "\tCurrent:" << current + // << endl; + /* Restore the heap copy back into the C stack */ + if (this->_stack_saved != 0) { + memcpy(this->_stack_start, this->stack_copy, this->_stack_saved); + this->free_stack_copy(); + } + StackState* owner = const_cast(¤t); + if (!owner->_stack_start) { + owner = owner->stack_prev; /* greenlet is dying, skip it */ + } + while (owner && owner->stack_stop <= this->stack_stop) { + // cerr << "\tOwner: " << owner << endl; + owner = owner->stack_prev; /* find greenlet with more stack */ + } + this->stack_prev = owner; + // cerr << "\tFinished with: " << *this << endl; +} + +inline int StackState::copy_stack_to_heap_up_to(const char* const stop) G_NOEXCEPT +{ + /* Save more of g's stack into the heap -- at least up to 'stop' + g->stack_stop |________| + | | + | __ stop . . . . . + | | ==> . . + |________| _______ + | | | | + | | | | + g->stack_start | | |_______| g->stack_copy + */ + intptr_t sz1 = this->_stack_saved; + intptr_t sz2 = stop - this->_stack_start; + assert(this->_stack_start); + if (sz2 > sz1) { + char* c = (char*)PyMem_Realloc(this->stack_copy, sz2); + if (!c) { + PyErr_NoMemory(); + return -1; + } + memcpy(c + sz1, this->_stack_start + sz1, sz2 - sz1); + this->stack_copy = c; + this->_stack_saved = sz2; + } + return 0; +} + +inline int StackState::copy_stack_to_heap(char* const stackref, + const StackState& current) G_NOEXCEPT +{ + // cerr << "copy_stack_to_heap: " << endl + // << "\tstackref: " << (void*)stackref << endl + // << "\tthis: " << *this << endl + // << "\tcurrent: " << current + // << endl; + /* must free all the C stack up to target_stop */ + const char* const target_stop = this->stack_stop; + + StackState* owner = const_cast(¤t); + assert(owner->_stack_saved == 0); // everything is present on the stack + if (!owner->_stack_start) { + // cerr << "\tcurrent is dead; using: " << owner->stack_prev << endl; + owner = owner->stack_prev; /* not saved if dying */ + } + else { + owner->_stack_start = stackref; + } + + while (owner->stack_stop < target_stop) { + // cerr << "\tCopying from " << *owner << endl; + /* ts_current is entierely within the area to free */ + if (owner->copy_stack_to_heap_up_to(owner->stack_stop)) { + return -1; /* XXX */ + } + owner = owner->stack_prev; + } + if (owner != this) { + if (owner->copy_stack_to_heap_up_to(target_stop)) { + return -1; /* XXX */ + } + } + return 0; +} + +inline bool StackState::started() const G_NOEXCEPT +{ + return this->stack_stop != nullptr; +} + +inline bool StackState::main() const G_NOEXCEPT +{ + return this->stack_stop == (char*)-1; +} + +inline bool StackState::active() const G_NOEXCEPT +{ + return this->_stack_start != nullptr; +} + +inline void StackState::set_active() G_NOEXCEPT +{ + assert(this->_stack_start == nullptr); + this->_stack_start = (char*)1; +} + +inline void StackState::set_inactive() G_NOEXCEPT +{ + this->_stack_start = nullptr; + // XXX: What if we still have memory out there? + // That case is actually triggered by + // test_issue251_issue252_explicit_reference_not_collectable (greenlet.tests.test_leaks.TestLeaks) + // and + // test_issue251_issue252_need_to_collect_in_background + // (greenlet.tests.test_leaks.TestLeaks) + // + // Those objects never get deallocated, so the destructor never + // runs. + // It *seems* safe to clean up the memory here? + if (this->_stack_saved) { + this->free_stack_copy(); + } +} + +inline intptr_t StackState::stack_saved() const G_NOEXCEPT +{ + return this->_stack_saved; +} + +inline char* StackState::stack_start() const G_NOEXCEPT +{ + return this->_stack_start; +} + + +inline StackState StackState::make_main() G_NOEXCEPT +{ + StackState s; + s._stack_start = (char*)1; + s.stack_stop = (char*)-1; + return s; +} + +StackState::~StackState() +{ + if (this->_stack_saved != 0) { + this->free_stack_copy(); + } +} + +using greenlet::Greenlet; + +bool Greenlet::is_currently_running_in_some_thread() const +{ + return this->stack_state.active() && !this->python_state.top_frame(); +} + + + +#endif diff --git a/.venv/Lib/site-packages/greenlet/greenlet_internal.hpp b/.venv/Lib/site-packages/greenlet/greenlet_internal.hpp new file mode 100644 index 000000000..4f7fe6bb7 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/greenlet_internal.hpp @@ -0,0 +1,106 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +#ifndef GREENLET_INTERNAL_H +#define GREENLET_INTERNAL_H +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunused-function" +# pragma clang diagnostic ignored "-Wmissing-field-initializers" +# pragma clang diagnostic ignored "-Wunused-variable" +#endif + +/** + * Implementation helpers. + * + * C++ templates and inline functions should go here. + */ +#define PY_SSIZE_T_CLEAN +#include "greenlet_compiler_compat.hpp" +#include "greenlet_cpython_compat.hpp" +#include "greenlet_exceptions.hpp" +#include "greenlet_greenlet.hpp" +#include "greenlet_allocator.hpp" + +#include +#include + +#define GREENLET_MODULE +struct _greenlet; +typedef struct _greenlet PyGreenlet; +namespace greenlet { + + class ThreadState; + +}; + + +#define implementation_ptr_t greenlet::Greenlet* + + +#include "greenlet.h" + +G_FP_TMPL_STATIC inline void +greenlet::refs::MainGreenletExactChecker(void *p) +{ + if (!p) { + return; + } + // We control the class of the main greenlet exactly. + if (Py_TYPE(p) != &PyGreenlet_Type) { + std::string err("MainGreenlet: Expected exactly a greenlet, not a "); + err += Py_TYPE(p)->tp_name; + throw greenlet::TypeError(err); + } + + // Greenlets from dead threads no longer respond to main() with a + // true value; so in that case we need to perform an additional + // check. + Greenlet* g = ((PyGreenlet*)p)->pimpl; + if (g->main()) { + return; + } + if (!dynamic_cast(g)) { + std::string err("MainGreenlet: Expected exactly a main greenlet, not a "); + err += Py_TYPE(p)->tp_name; + throw greenlet::TypeError(err); + } +} + + + +template +inline greenlet::Greenlet* greenlet::refs::_OwnedGreenlet::operator->() const G_NOEXCEPT +{ + return reinterpret_cast(this->p)->pimpl; +} + +template +inline greenlet::Greenlet* greenlet::refs::_BorrowedGreenlet::operator->() const G_NOEXCEPT +{ + return reinterpret_cast(this->p)->pimpl; +} + +#include +#include + + +extern PyTypeObject PyGreenlet_Type; + + + +/** + * Forward declarations needed in multiple files. + */ +static PyGreenlet* green_create_main(greenlet::ThreadState*); +static PyObject* green_switch(PyGreenlet* self, PyObject* args, PyObject* kwargs); +static int green_is_gc(BorrowedGreenlet self); + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + + +#endif + +// Local Variables: +// flycheck-clang-include-path: ("../../include" "/opt/local/Library/Frameworks/Python.framework/Versions/3.10/include/python3.10") +// End: diff --git a/.venv/Lib/site-packages/greenlet/greenlet_refs.hpp b/.venv/Lib/site-packages/greenlet/greenlet_refs.hpp new file mode 100644 index 000000000..ed1ef195c --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/greenlet_refs.hpp @@ -0,0 +1,1062 @@ +#ifndef GREENLET_REFS_HPP +#define GREENLET_REFS_HPP + +#define PY_SSIZE_T_CLEAN +#include +//#include "greenlet_internal.hpp" +#include "greenlet_compiler_compat.hpp" +#include "greenlet_cpython_compat.hpp" +#include "greenlet_exceptions.hpp" + +struct _greenlet; +struct _PyMainGreenlet; + +typedef struct _greenlet PyGreenlet; +extern PyTypeObject PyGreenlet_Type; + + +#ifdef GREENLET_USE_STDIO +#include +using std::cerr; +using std::endl; +#endif + +namespace greenlet +{ + class Greenlet; + + namespace refs + { + // Type checkers throw a TypeError if the argument is not + // null, and isn't of the required Python type. + // (We can't use most of the defined type checkers + // like PyList_Check, etc, directly, because they are + // implemented as macros.) + typedef void (*TypeChecker)(void*); + + G_FP_TMPL_STATIC inline void + NoOpChecker(void*) + { + return; + } + + G_FP_TMPL_STATIC inline void + GreenletChecker(void *p) + { + if (!p) { + return; + } + + PyTypeObject* typ = Py_TYPE(p); + // fast, common path. (PyObject_TypeCheck is a macro or + // static inline function, and it also does a + // direct comparison of the type pointers, but its fast + // path only handles one type) + if (typ == &PyGreenlet_Type) { + return; + } + + if (!PyObject_TypeCheck(p, &PyGreenlet_Type)) { + std::string err("GreenletChecker: Expected any type of greenlet, not "); + err += Py_TYPE(p)->tp_name; + throw TypeError(err); + } + } + + G_FP_TMPL_STATIC inline void + MainGreenletExactChecker(void *p); + + template + class PyObjectPointer; + + template + class OwnedReference; + + + template + class BorrowedReference; + + typedef BorrowedReference BorrowedObject; + typedef OwnedReference OwnedObject; + + class ImmortalObject; + + template + class _OwnedGreenlet; + + typedef _OwnedGreenlet OwnedGreenlet; + typedef _OwnedGreenlet OwnedMainGreenlet; + + template + class _BorrowedGreenlet; + + typedef _BorrowedGreenlet BorrowedGreenlet; + + G_FP_TMPL_STATIC inline void + ContextExactChecker(void *p) + { + if (!p) { + return; + } +#if GREENLET_PY37 + if (!PyContext_CheckExact(p)) { + throw TypeError( + "greenlet context must be a contextvars.Context or None" + ); + } +#endif + } + + typedef OwnedReference OwnedContext; + } +} + +namespace greenlet { + + + namespace refs { + // A set of classes to make reference counting rules in python + // code explicit. + // + // Rules of use: + // (1) Functions returning a new reference that the caller of the + // function is expected to dispose of should return a + // ``OwnedObject`` object. This object automatically releases its + // reference when it goes out of scope. It works like a ``std::shared_ptr`` + // and can be copied or used as a function parameter (but don't do + // that). Note that constructing a ``OwnedObject`` from a + // PyObject* steals the reference. + // (2) Parameters to functions should be either a + // ``OwnedObject&``, or, more generally, a ``PyObjectPointer&``. + // If the function needs to create its own new reference, it can + // do so by copying to a local ``OwnedObject``. + // (3) Functions returning an existing pointer that is NOT + // incref'd, and which the caller MUST NOT decref, + // should return a ``BorrowedObject``. + + // + // For a class with a single pointer member, whose constructor + // does nothing but copy a pointer parameter into the member, and + // which can then be converted back to the pointer type, compilers + // generate code that's the same as just passing the pointer. + // That is, func(BorrowedObject x) called like ``PyObject* p = + // ...; f(p)`` has 0 overhead. Similarly, they "unpack" to the + // pointer type with 0 overhead. + // + // If there are no virtual functions, no complex inheritance (maybe?) and + // no destructor, these can be directly used as parameters in + // Python callbacks like tp_init: the layout is the same as a + // single pointer. Only subclasses with trivial constructors that + // do nothing but set the single pointer member are safe to use + // that way. + + + // This is the base class for things that can be done with a + // PyObject pointer. It assumes nothing about memory management. + // NOTE: Nothing is virtual, so subclasses shouldn't add new + // storage fields or try to override these methods. + template + class PyObjectPointer + { + public: + typedef T PyType; + protected: + T* p; + public: + explicit PyObjectPointer(T* it=nullptr) : p(it) + { + TC(p); + } + + // We don't allow automatic casting to PyObject* at this + // level, because then we could be passed to Py_DECREF/INCREF, + // but we want nothing to do with memory management. If you + // know better, then you can use the get() method, like on a + // std::shared_ptr. Except we name it borrow() to clarify that + // if this is a reference-tracked object, the pointer you get + // back will go away when the object does. + // TODO: This should probably not exist here, but be moved + // down to relevant sub-types. + + inline T* borrow() const G_NOEXCEPT + { + return this->p; + } + + PyObject* borrow_o() const G_NOEXCEPT + { + return reinterpret_cast(this->p); + } + + inline T* operator->() const G_NOEXCEPT + { + return this->p; + } + + bool is_None() const G_NOEXCEPT + { + return this->p == Py_None; + } + + inline PyObject* acquire_or_None() const G_NOEXCEPT + { + PyObject* result = this->p ? reinterpret_cast(this->p) : Py_None; + Py_INCREF(result); + return result; + } + + G_EXPLICIT_OP operator bool() const G_NOEXCEPT + { + return p != nullptr; + } + + inline Py_ssize_t REFCNT() const G_NOEXCEPT + { + return p ? Py_REFCNT(p) : -42; + } + + inline PyTypeObject* TYPE() const G_NOEXCEPT + { + return p ? Py_TYPE(p) : nullptr; + } + + inline OwnedObject PyStr() const G_NOEXCEPT; + inline const std::string as_str() const G_NOEXCEPT; + inline OwnedObject PyGetAttr(const ImmortalObject& name) const G_NOEXCEPT; + inline OwnedObject PyRequireAttr(const char* const name) const; + inline OwnedObject PyRequireAttr(const ImmortalObject& name) const; + inline OwnedObject PyCall(const BorrowedObject& arg) const; + inline OwnedObject PyCall(PyGreenlet* arg) const ; + inline OwnedObject PyCall(PyObject* arg) const ; + // PyObject_Call(this, args, kwargs); + inline OwnedObject PyCall(const BorrowedObject args, + const BorrowedObject kwargs) const; + inline OwnedObject PyCall(const OwnedObject& args, + const OwnedObject& kwargs) const; + + protected: + void _set_raw_pointer(void* t) + { + TC(t); + p = reinterpret_cast(t); + } + void* _get_raw_pointer() const + { + return p; + } + }; + +#ifdef GREENLET_USE_STDIO + template + std::ostream& operator<<(std::ostream& os, const PyObjectPointer& s) + { + const std::type_info& t = typeid(s); + os << t.name() + << "(addr=" << s.borrow() + << ", refcnt=" << s.REFCNT() + << ", value=" << s.as_str() + << ")"; + + return os; + } +#endif + + template + inline bool operator==(const PyObjectPointer& lhs, const void* const rhs) G_NOEXCEPT + { + return lhs.borrow_o() == rhs; + } + + template + inline bool operator==(const PyObjectPointer& lhs, const PyObjectPointer& rhs) G_NOEXCEPT + { + return lhs.borrow_o() == rhs.borrow_o(); + } + + template + inline bool operator!=(const PyObjectPointer& lhs, + const PyObjectPointer& rhs) G_NOEXCEPT + { + return lhs.borrow_o() != rhs.borrow_o(); + } + + template + class OwnedReference : public PyObjectPointer + { + private: + friend class OwnedList; + + protected: + explicit OwnedReference(T* it) : PyObjectPointer(it) + { + } + + public: + + // Constructors + + static OwnedReference consuming(PyObject* p) + { + return OwnedReference(reinterpret_cast(p)); + } + + static OwnedReference owning(T* p) + { + OwnedReference result(p); + Py_XINCREF(result.p); + return result; + } + + OwnedReference() : PyObjectPointer(nullptr) + {} + + explicit OwnedReference(const PyObjectPointer<>& other) + : PyObjectPointer(nullptr) + { + T* op = other.borrow(); + TC(op); + this->p = other.borrow(); + Py_XINCREF(this->p); + } + + // It would be good to make use of the C++11 distinction + // between move and copy operations, e.g., constructing from a + // pointer should be a move operation. + // In the common case of ``OwnedObject x = Py_SomeFunction()``, + // the call to the copy constructor will be elided completely. + OwnedReference(const OwnedReference& other) + : PyObjectPointer(other.p) + { + Py_XINCREF(this->p); + } + + static OwnedReference None() + { + Py_INCREF(Py_None); + return OwnedReference(Py_None); + } + + // We can assign from exactly our type without any extra checking + OwnedReference& operator=(const OwnedReference& other) + { + Py_XINCREF(other.p); + const T* tmp = this->p; + this->p = other.p; + Py_XDECREF(tmp); + return *this; + } + + OwnedReference& operator=(const BorrowedReference other) + { + return this->operator=(other.borrow()); + } + + OwnedReference& operator=(T* const other) + { + TC(other); + Py_XINCREF(other); + T* tmp = this->p; + this->p = other; + Py_XDECREF(tmp); + return *this; + } + + // We can assign from an arbitrary reference type + // if it passes our check. + template + OwnedReference& operator=(const OwnedReference& other) + { + X* op = other.borrow(); + TC(op); + return this->operator=(reinterpret_cast(op)); + } + + inline void steal(T* other) + { + assert(this->p == nullptr); + TC(other); + this->p = other; + } + + T* relinquish_ownership() + { + T* result = this->p; + this->p = nullptr; + return result; + } + + T* acquire() const + { + // Return a new reference. + // TODO: This may go away when we have reference objects + // throughout the code. + Py_XINCREF(this->p); + return this->p; + } + + // Nothing else declares a destructor, we're the leaf, so we + // should be able to get away without virtual. + ~OwnedReference() + { + Py_CLEAR(this->p); + } + + void CLEAR() + { + Py_CLEAR(this->p); + assert(this->p == nullptr); + } + }; + + static inline + void operator<<=(PyObject*& target, OwnedObject& o) + { + target = o.relinquish_ownership(); + } + + class NewReference : public OwnedObject + { + private: + G_NO_COPIES_OF_CLS(NewReference); + public: + // Consumes the reference. Only use this + // for API return values. + NewReference(PyObject* it) : OwnedObject(it) + { + } + }; + + class NewDictReference : public NewReference + { + private: + G_NO_COPIES_OF_CLS(NewDictReference); + public: + NewDictReference() : NewReference(PyDict_New()) + { + if (!this->p) { + throw PyErrOccurred(); + } + } + + void SetItem(const char* const key, PyObject* value) + { + Require(PyDict_SetItemString(this->p, key, value)); + } + + void SetItem(const PyObjectPointer<>& key, PyObject* value) + { + Require(PyDict_SetItem(this->p, key.borrow_o(), value)); + } + }; + + template + class _OwnedGreenlet: public OwnedReference + { + private: + protected: + _OwnedGreenlet(T* it) : OwnedReference(it) + {} + + public: + _OwnedGreenlet() : OwnedReference() + {} + + _OwnedGreenlet(const _OwnedGreenlet& other) : OwnedReference(other) + { + } + _OwnedGreenlet(OwnedMainGreenlet& other) : + OwnedReference(reinterpret_cast(other.acquire())) + { + } + _OwnedGreenlet(const BorrowedGreenlet& other); + // Steals a reference. + static _OwnedGreenlet consuming(PyGreenlet* it) + { + return _OwnedGreenlet(reinterpret_cast(it)); + } + + inline _OwnedGreenlet& operator=(const OwnedGreenlet& other) + { + return this->operator=(other.borrow()); + } + + inline _OwnedGreenlet& operator=(const BorrowedGreenlet& other); + + _OwnedGreenlet& operator=(const OwnedMainGreenlet& other) + { + PyGreenlet* owned = other.acquire(); + Py_XDECREF(this->p); + this->p = reinterpret_cast(owned); + return *this; + } + + _OwnedGreenlet& operator=(T* const other) + { + OwnedReference::operator=(other); + return *this; + } + + T* relinquish_ownership() + { + T* result = this->p; + this->p = nullptr; + return result; + } + + PyObject* relinquish_ownership_o() + { + return reinterpret_cast(relinquish_ownership()); + } + + inline Greenlet* operator->() const G_NOEXCEPT; + inline operator Greenlet*() const G_NOEXCEPT; + }; + + template + class BorrowedReference : public PyObjectPointer + { + public: + // Allow implicit creation from PyObject* pointers as we + // transition to using these classes. Also allow automatic + // conversion to PyObject* for passing to C API calls and even + // for Py_INCREF/DECREF, because we ourselves do no memory management. + BorrowedReference(T* it) : PyObjectPointer(it) + {} + + BorrowedReference(const PyObjectPointer& ref) : PyObjectPointer(ref.borrow()) + {} + + BorrowedReference() : PyObjectPointer(nullptr) + {} + + operator T*() const + { + return this->p; + } + }; + + typedef BorrowedReference BorrowedObject; + //typedef BorrowedReference BorrowedGreenlet; + + template + class _BorrowedGreenlet : public BorrowedReference + { + public: + _BorrowedGreenlet() : + BorrowedReference(nullptr) + {} + + _BorrowedGreenlet(T* it) : + BorrowedReference(it) + {} + + _BorrowedGreenlet(const BorrowedObject& it); + + _BorrowedGreenlet(const OwnedGreenlet& it) : + BorrowedReference(it.borrow()) + {} + + _BorrowedGreenlet& operator=(const BorrowedObject& other); + + // We get one of these for PyGreenlet, but one for PyObject + // is handy as well + operator PyObject*() const + { + return reinterpret_cast(this->p); + } + inline Greenlet* operator->() const G_NOEXCEPT; + inline operator Greenlet*() const G_NOEXCEPT; + }; + + typedef _BorrowedGreenlet BorrowedGreenlet; + + template + _OwnedGreenlet::_OwnedGreenlet(const BorrowedGreenlet& other) + : OwnedReference(reinterpret_cast(other.borrow())) + { + Py_XINCREF(this->p); + } + + + class BorrowedMainGreenlet + : public _BorrowedGreenlet + { + public: + BorrowedMainGreenlet(const OwnedMainGreenlet& it) : + _BorrowedGreenlet(it.borrow()) + {} + BorrowedMainGreenlet(PyGreenlet* it=nullptr) + : _BorrowedGreenlet(it) + {} + }; + + template + _OwnedGreenlet& _OwnedGreenlet::operator=(const BorrowedGreenlet& other) + { + return this->operator=(other.borrow()); + } + + + class ImmortalObject : public PyObjectPointer<> + { + private: + G_NO_ASSIGNMENT_OF_CLS(ImmortalObject); + public: + explicit ImmortalObject(PyObject* it) : PyObjectPointer<>(it) + { + } + + /** + * Become the new owner of the object. Does not change the + * reference count. + */ + ImmortalObject& operator=(PyObject* it) + { + assert(this->p == nullptr); + this->p = it; + return *this; + } + + static ImmortalObject consuming(PyObject* it) + { + return ImmortalObject(it); + } + + inline operator PyObject*() const + { + return this->p; + } + }; + + class ImmortalString : public ImmortalObject + { + private: + G_NO_COPIES_OF_CLS(ImmortalString); + const char* str; + public: + ImmortalString(const char* const str) : + ImmortalObject(str ? Require(Greenlet_Intern(str)) : nullptr) + { + this->str = str; + } + + inline ImmortalString& operator=(const char* const str) + { + if (!this->p) { + this->p = Require(Greenlet_Intern(str)); + this->str = str; + } + else { + assert(this->str == str); + } + return *this; + } + + }; + + template + inline OwnedObject PyObjectPointer::PyStr() const G_NOEXCEPT + { + if (!this->p) { + return OwnedObject(); + } + return OwnedObject::consuming(PyObject_Str(reinterpret_cast(this->p))); + } + + template + inline const std::string PyObjectPointer::as_str() const G_NOEXCEPT + { + // NOTE: This is not Python exception safe. + if (this->p) { + // The Python APIs return a cached char* value that's only valid + // as long as the original object stays around, and we're + // about to (probably) toss it. Hence the copy to std::string. + OwnedObject py_str = this->PyStr(); + if (!py_str) { + return "(nil)"; + } +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_AsUTF8(py_str.borrow()); +#else + return PyString_AsString(py_str.borrow()); +#endif + } + return "(nil)"; + } + + template + inline OwnedObject PyObjectPointer::PyGetAttr(const ImmortalObject& name) const G_NOEXCEPT + { + assert(this->p); + return OwnedObject::consuming(PyObject_GetAttr(reinterpret_cast(this->p), name)); + } + + template + inline OwnedObject PyObjectPointer::PyRequireAttr(const char* const name) const + { + assert(this->p); + return OwnedObject::consuming(Require(PyObject_GetAttrString(this->p, name))); + } + + template + inline OwnedObject PyObjectPointer::PyRequireAttr(const ImmortalObject& name) const + { + assert(this->p); + return OwnedObject::consuming(Require( + PyObject_GetAttr(reinterpret_cast(this->p), + name))); + } + + template + inline OwnedObject PyObjectPointer::PyCall(const BorrowedObject& arg) const + { + return this->PyCall(arg.borrow()); + } + + template + inline OwnedObject PyObjectPointer::PyCall(PyGreenlet* arg) const + { + return this->PyCall(reinterpret_cast(arg)); + } + + template + inline OwnedObject PyObjectPointer::PyCall(PyObject* arg) const + { + assert(this->p); + return OwnedObject::consuming(PyObject_CallFunctionObjArgs(this->p, arg, NULL)); + } + + template + inline OwnedObject PyObjectPointer::PyCall(const BorrowedObject args, + const BorrowedObject kwargs) const + { + assert(this->p); + return OwnedObject::consuming(PyObject_Call(this->p, args, kwargs)); + } + + template + inline OwnedObject PyObjectPointer::PyCall(const OwnedObject& args, + const OwnedObject& kwargs) const + { + assert(this->p); + return OwnedObject::consuming(PyObject_Call(this->p, args.borrow(), kwargs.borrow())); + } + + G_FP_TMPL_STATIC inline void + ListChecker(void * p) + { + if (!p) { + return; + } + if (!PyList_Check(p)) { + throw TypeError("Expected a list"); + } + } + + class OwnedList : public OwnedReference + { + private: + G_NO_ASSIGNMENT_OF_CLS(OwnedList); + public: + // TODO: Would like to use move. + explicit OwnedList(const OwnedObject& other) + : OwnedReference(other) + { + } + + OwnedList& operator=(const OwnedObject& other) + { + if (other && PyList_Check(other.p)) { + // Valid list. Own a new reference to it, discard the + // reference to what we did own. + PyObject* new_ptr = other.p; + Py_INCREF(new_ptr); + Py_XDECREF(this->p); + this->p = new_ptr; + } + else { + // Either the other object was NULL (an error) or it + // wasn't a list. Either way, we're now invalidated. + Py_XDECREF(this->p); + this->p = nullptr; + } + return *this; + } + + inline bool empty() const + { + return PyList_GET_SIZE(p) == 0; + } + + inline Py_ssize_t size() const + { + return PyList_GET_SIZE(p); + } + + inline BorrowedObject at(const Py_ssize_t index) const + { + return PyList_GET_ITEM(p, index); + } + + inline void clear() + { + PyList_SetSlice(p, 0, PyList_GET_SIZE(p), NULL); + } + }; + + // Use this to represent the module object used at module init + // time. + // This could either be a borrowed (Py2) or new (Py3) reference; + // either way, we don't want to do any memory management + // on it here, Python itself will handle that. + // XXX: Actually, that's not quite right. On Python 3, if an + // exception occurs before we return to the interpreter, this will + // leak; but all previous versions also had that problem. + class CreatedModule : public PyObjectPointer<> + { + private: + G_NO_COPIES_OF_CLS(CreatedModule); + public: + CreatedModule(PyModuleDef& mod_def) : PyObjectPointer<>( + Require(PyModule_Create(&mod_def))) + { + } + + // PyAddObject(): Add a reference to the object to the module. + // On return, the reference count of the object is unchanged. + // + // The docs warn that PyModule_AddObject only steals the + // reference on success, so if it fails after we've incref'd + // or allocated, we're responsible for the decref. + void PyAddObject(const char* name, const long new_bool) + { + OwnedObject p = OwnedObject::consuming(Require(PyBool_FromLong(new_bool))); + this->PyAddObject(name, p); + } + + void PyAddObject(const char* name, const OwnedObject& new_object) + { + // The caller already owns a reference they will decref + // when their variable goes out of scope, we still need to + // incref/decref. + this->PyAddObject(name, new_object.borrow()); + } + + void PyAddObject(const char* name, const ImmortalObject& new_object) + { + this->PyAddObject(name, new_object.borrow()); + } + + void PyAddObject(const char* name, PyTypeObject& type) + { + this->PyAddObject(name, reinterpret_cast(&type)); + } + + void PyAddObject(const char* name, PyObject* new_object) + { + Py_INCREF(new_object); + try { + Require(PyModule_AddObject(this->p, name, new_object)); + } + catch (const PyErrOccurred&) { + Py_DECREF(p); + throw; + } + } + }; + + class PyErrFetchParam : public PyObjectPointer<> + { + // Not an owned object, because we can't be initialized with + // one, and we only sometimes acquire ownership. + private: + G_NO_COPIES_OF_CLS(PyErrFetchParam); + public: + // To allow declaring these and passing them to + // PyErr_Fetch we implement the empty constructor, + // and the address operator. + PyErrFetchParam() : PyObjectPointer<>(nullptr) + { + } + + PyObject** operator&() + { + return &this->p; + } + + // This allows us to pass one directly without the &, + // BUT it has higher precedence than the bool operator + // if it's not explicit. + operator PyObject**() + { + return &this->p; + } + + // We don't want to be able to pass these to Py_DECREF and + // such so we don't have the implicit PyObject* conversion. + + inline PyObject* relinquish_ownership() + { + PyObject* result = this->p; + this->p = nullptr; + return result; + } + + ~PyErrFetchParam() + { + Py_XDECREF(p); + } + }; + + class OwnedErrPiece : public OwnedObject + { + private: + + public: + // Unlike OwnedObject, this increments the refcount. + OwnedErrPiece(PyObject* p=nullptr) : OwnedObject(p) + { + this->acquire(); + } + + PyObject** operator&() + { + return &this->p; + } + + inline operator PyObject*() const + { + return this->p; + } + + operator PyTypeObject*() const + { + return reinterpret_cast(this->p); + } + }; + + class PyErrPieces + { + private: + OwnedErrPiece type; + OwnedErrPiece instance; + OwnedErrPiece traceback; + bool restored; + public: + // Takes new references; if we're destroyed before + // restoring the error, we drop the references. + PyErrPieces(PyObject* t, PyObject* v, PyObject* tb) : + type(t), + instance(v), + traceback(tb), + restored(0) + { + this->normalize(); + } + + PyErrPieces() : + restored(0) + { + // PyErr_Fetch transfers ownership to us, so + // we don't actually need to INCREF; but we *do* + // need to DECREF if we're not restored. + PyErrFetchParam t, v, tb; + PyErr_Fetch(&t, &v, &tb); + type.steal(t.relinquish_ownership()); + instance.steal(v.relinquish_ownership()); + traceback.steal(tb.relinquish_ownership()); + } + + void PyErrRestore() + { + // can only do this once + assert(!this->restored); + this->restored = true; + PyErr_Restore( + this->type.relinquish_ownership(), + this->instance.relinquish_ownership(), + this->traceback.relinquish_ownership()); + assert(!this->type && !this->instance && !this->traceback); + } + + private: + void normalize() + { + // First, check the traceback argument, replacing None, + // with NULL + if (traceback.is_None()) { + traceback = nullptr; + } + + if (traceback && !PyTraceBack_Check(traceback.borrow())) { + throw PyErrOccurred(PyExc_TypeError, + "throw() third argument must be a traceback object"); + } + + if (PyExceptionClass_Check(type)) { + // If we just had a type, we'll now have a type and + // instance. + // The type's refcount will have gone up by one + // because of the instance and the instance will have + // a refcount of one. Either way, we owned, and still + // do own, exactly one reference. + PyErr_NormalizeException(&type, &instance, &traceback); + + } + else if (PyExceptionInstance_Check(type)) { + /* Raising an instance --- usually that means an + object that is a subclass of BaseException, but on + Python 2, that can also mean an arbitrary old-style + object. The value should be a dummy. */ + if (instance && !instance.is_None()) { + throw PyErrOccurred( + PyExc_TypeError, + "instance exception may not have a separate value"); + } + /* Normalize to raise , */ + this->instance = this->type; + this->type = PyExceptionInstance_Class(instance.borrow()); + + /* + It would be tempting to do this: + + Py_ssize_t type_count = Py_REFCNT(Py_TYPE(instance.borrow())); + this->type = PyExceptionInstance_Class(instance.borrow()); + assert(this->type.REFCNT() == type_count + 1); + + But that doesn't work on Python 2 in the case of + old-style instances: The result of Py_TYPE is going to + be the global shared that all + old-style classes have, while the return of Instance_Class() + will be the Python-level class object. The two are unrelated. + */ + } + else { + /* Not something you can raise. throw() fails. */ + PyErr_Format(PyExc_TypeError, + "exceptions must be classes, or instances, not %s", + Py_TYPE(type.borrow())->tp_name); + throw PyErrOccurred(); + } + } + }; + + // PyArg_Parse's O argument returns a borrowed reference. + class PyArgParseParam : public BorrowedObject + { + private: + G_NO_COPIES_OF_CLS(PyArgParseParam); + public: + explicit PyArgParseParam(PyObject* p=nullptr) : BorrowedObject(p) + { + } + + inline PyObject** operator&() + { + return &this->p; + } + }; + +};}; + +#endif diff --git a/.venv/Lib/site-packages/greenlet/greenlet_slp_switch.hpp b/.venv/Lib/site-packages/greenlet/greenlet_slp_switch.hpp new file mode 100644 index 000000000..25ac5ab35 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/greenlet_slp_switch.hpp @@ -0,0 +1,117 @@ +#ifndef GREENLET_SLP_SWITCH_HPP +#define GREENLET_SLP_SWITCH_HPP + +#include "greenlet_compiler_compat.hpp" +#include "greenlet_refs.hpp" + +/* + * the following macros are spliced into the OS/compiler + * specific code, in order to simplify maintenance. + */ +// We can save about 10% of the time it takes to switch greenlets if +// we thread the thread state through the slp_save_state() and the +// following slp_restore_state() calls from +// slp_switch()->g_switchstack() (which already needs to access it). +// +// However: +// +// that requires changing the prototypes and implementations of the +// switching functions. If we just change the prototype of +// slp_switch() to accept the argument and update the macros, without +// changing the implementation of slp_switch(), we get crashes on +// 64-bit Linux and 32-bit x86 (for reasons that aren't 100% clear); +// on the other hand, 64-bit macOS seems to be fine. Also, 64-bit +// windows is an issue because slp_switch is written fully in assembly +// and currently ignores its argument so some code would have to be +// adjusted there to pass the argument on to the +// ``slp_save_state_asm()`` function (but interestingly, because of +// the calling convention, the extra argument is just ignored and +// things function fine, albeit slower, if we just modify +// ``slp_save_state_asm`()` to fetch the pointer to pass to the +// macro.) +// +// Our compromise is to use a *glabal*, untracked, weak, pointer +// to the necessary thread state during the process of switching only. +// This is safe because we're protected by the GIL, and if we're +// running this code, the thread isn't exiting. This also nets us a +// 10-12% speed improvement. + +static greenlet::Greenlet* volatile switching_thread_state = nullptr; + + +#ifdef GREENLET_NOINLINE_SUPPORTED +extern "C" { +static int GREENLET_NOINLINE(slp_save_state_trampoline)(char* stackref); +static void GREENLET_NOINLINE(slp_restore_state_trampoline)(); +} +#define GREENLET_NOINLINE_INIT() \ + do { \ + } while (0) +#else +/* force compiler to call functions via pointers */ +/* XXX: Do we even want/need to support such compilers? This code path + is untested on CI. */ +extern "C" { +static int (slp_save_state_trampoline)(char* stackref); +static void (slp_restore_state_trampoline)(); +} +#define GREENLET_NOINLINE(name) cannot_inline_##name +#define GREENLET_NOINLINE_INIT() \ + do { \ + slp_save_state_trampoline = GREENLET_NOINLINE(slp_save_state_trampoline); \ + slp_restore_state_trampoline = GREENLET_NOINLINE(slp_restore_state_trampoline); \ + } while (0) +#endif + +#define SLP_SAVE_STATE(stackref, stsizediff) \ +do { \ + assert(switching_thread_state); \ + stackref += STACK_MAGIC; \ + if (slp_save_state_trampoline((char*)stackref)) \ + return -1; \ + if (!switching_thread_state->active()) \ + return 1; \ + stsizediff = switching_thread_state->stack_start() - (char*)stackref; \ +} while (0) + +#define SLP_RESTORE_STATE() slp_restore_state_trampoline() + +#define SLP_EVAL +extern "C" { +#define slp_switch GREENLET_NOINLINE(slp_switch) +#include "slp_platformselect.h" +} +#undef slp_switch + +#ifndef STACK_MAGIC +# error \ + "greenlet needs to be ported to this platform, or taught how to detect your compiler properly." +#endif /* !STACK_MAGIC */ + + + +#ifdef EXTERNAL_ASM +/* CCP addition: Make these functions, to be called from assembler. + * The token include file for the given platform should enable the + * EXTERNAL_ASM define so that this is included. + */ +extern "C" { +intptr_t +slp_save_state_asm(intptr_t* ref) +{ + intptr_t diff; + SLP_SAVE_STATE(ref, diff); + return diff; +} + +void +slp_restore_state_asm(void) +{ + SLP_RESTORE_STATE(); +} + +extern int slp_switch(void); +}; +#endif + +#endif diff --git a/.venv/Lib/site-packages/greenlet/greenlet_thread_state.hpp b/.venv/Lib/site-packages/greenlet/greenlet_thread_state.hpp new file mode 100644 index 000000000..b740874e1 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/greenlet_thread_state.hpp @@ -0,0 +1,561 @@ +#ifndef GREENLET_THREAD_STATE_HPP +#define GREENLET_THREAD_STATE_HPP + +#include +#include + +#include "greenlet_internal.hpp" +#include "greenlet_refs.hpp" +#include "greenlet_thread_support.hpp" + +using greenlet::refs::BorrowedObject; +using greenlet::refs::BorrowedGreenlet; +using greenlet::refs::BorrowedMainGreenlet; +using greenlet::refs::OwnedMainGreenlet; +using greenlet::refs::OwnedObject; +using greenlet::refs::OwnedGreenlet; +using greenlet::refs::OwnedList; +using greenlet::refs::PyErrFetchParam; +using greenlet::refs::PyArgParseParam; +using greenlet::refs::ImmortalString; +using greenlet::refs::CreatedModule; +using greenlet::refs::PyErrPieces; +using greenlet::refs::NewReference; + +namespace greenlet { +/** + * Thread-local state of greenlets. + * + * Each native thread will get exactly one of these objects, + * automatically accessed through the best available thread-local + * mechanism the compiler supports (``thread_local`` for C++11 + * compilers or ``__thread``/``declspec(thread)`` for older GCC/clang + * or MSVC, respectively.) + * + * Previously, we kept thread-local state mostly in a bunch of + * ``static volatile`` variables in the main greenlet file.. This had + * the problem of requiring extra checks, loops, and great care + * accessing these variables if we potentially invoked any Python code + * that could release the GIL, because the state could change out from + * under us. Making the variables thread-local solves this problem. + * + * When we detected that a greenlet API accessing the current greenlet + * was invoked from a different thread than the greenlet belonged to, + * we stored a reference to the greenlet in the Python thread + * dictionary for the thread the greenlet belonged to. This could lead + * to memory leaks if the thread then exited (because of a reference + * cycle, as greenlets referred to the thread dictionary, and deleting + * non-current greenlets leaked their frame plus perhaps arguments on + * the C stack). If a thread exited while still having running + * greenlet objects (perhaps that had just switched back to the main + * greenlet), and did not invoke one of the greenlet APIs *in that + * thread, immediately before it exited, without some other thread + * then being invoked*, such a leak was guaranteed. + * + * This can be partly solved by using compiler thread-local variables + * instead of the Python thread dictionary, thus avoiding a cycle. + * + * To fully solve this problem, we need a reliable way to know that a + * thread is done and we should clean up the main greenlet. On POSIX, + * we can use the destructor function of ``pthread_key_create``, but + * there's nothing similar on Windows; a C++11 thread local object + * reliably invokes its destructor when the thread it belongs to exits + * (non-C++11 compilers offer ``__thread`` or ``declspec(thread)`` to + * create thread-local variables, but they can't hold C++ objects that + * invoke destructors; the C++11 version is the most portable solution + * I found). When the thread exits, we can drop references and + * otherwise manipulate greenlets and frames that we know can no + * longer be switched to. For compilers that don't support C++11 + * thread locals, we have a solution that uses the python thread + * dictionary, though it may not collect everything as promptly as + * other compilers do, if some other library is using the thread + * dictionary and has a cycle or extra reference. + * + * There are two small wrinkles. The first is that when the thread + * exits, it is too late to actually invoke Python APIs: the Python + * thread state is gone, and the GIL is released. To solve *this* + * problem, our destructor uses ``Py_AddPendingCall`` to transfer the + * destruction work to the main thread. (This is not an issue for the + * dictionary solution.) + * + * The second is that once the thread exits, the thread local object + * is invalid and we can't even access a pointer to it, so we can't + * pass it to ``Py_AddPendingCall``. This is handled by actually using + * a second object that's thread local (ThreadStateCreator) and having + * it dynamically allocate this object so it can live until the + * pending call runs. + */ + + + +class ThreadState { +private: + // As of commit 08ad1dd7012b101db953f492e0021fb08634afad + // this class needed 56 bytes in o Py_DEBUG build + // on 64-bit macOS 11. + // Adding the vector takes us up to 80 bytes () + + /* Strong reference to the main greenlet */ + OwnedMainGreenlet main_greenlet; + + /* Strong reference to the current greenlet. */ + OwnedGreenlet current_greenlet; + + /* Strong reference to the trace function, if any. */ + OwnedObject tracefunc; + + typedef std::vector > deleteme_t; + /* A vector of raw PyGreenlet pointers representing things that need + deleted when this thread is running. The vector owns the + references, but you need to manually INCREF/DECREF as you use + them. We don't use a vector because we + make copy of this vector, and that would become O(n) as all the + refcounts are incremented in the copy. + */ + deleteme_t deleteme; + +#ifdef GREENLET_NEEDS_EXCEPTION_STATE_SAVED + void* exception_state; +#endif + + static std::clock_t _clocks_used_doing_gc; + static ImmortalString get_referrers_name; + static PythonAllocator allocator; + + G_NO_COPIES_OF_CLS(ThreadState); + +public: + static void* operator new(size_t UNUSED(count)) + { + return ThreadState::allocator.allocate(1); + } + + static void operator delete(void* ptr) + { + return ThreadState::allocator.deallocate(static_cast(ptr), + 1); + } + + static void init() + { + ThreadState::get_referrers_name = "get_referrers"; + ThreadState::_clocks_used_doing_gc = 0; + } + + ThreadState() + : main_greenlet(OwnedMainGreenlet::consuming(green_create_main(this))), + current_greenlet(main_greenlet) + { + if (!this->main_greenlet) { + // We failed to create the main greenlet. That's bad. + throw PyFatalError("Failed to create main greenlet"); + } + // The main greenlet starts with 1 refs: The returned one. We + // then copied it to the current greenlet. + assert(this->main_greenlet.REFCNT() == 2); + +#ifdef GREENLET_NEEDS_EXCEPTION_STATE_SAVED + this->exception_state = slp_get_exception_state(); +#endif + } + + inline void restore_exception_state() + { +#ifdef GREENLET_NEEDS_EXCEPTION_STATE_SAVED + // It's probably important this be inlined and only call C + // functions to avoid adding an SEH frame. + slp_set_exception_state(this->exception_state); +#endif + } + + inline bool has_main_greenlet() + { + return !!this->main_greenlet; + } + + // Called from the ThreadStateCreator when we're in non-standard + // threading mode. In that case, there is an object in the Python + // thread state dictionary that points to us. The main greenlet + // also traverses into us, in which case it's crucial not to + // traverse back into the main greenlet. + int tp_traverse(visitproc visit, void* arg, bool traverse_main=true) + { + if (traverse_main) { + Py_VISIT(main_greenlet.borrow_o()); + } + if (traverse_main || current_greenlet != main_greenlet) { + Py_VISIT(current_greenlet.borrow_o()); + } + Py_VISIT(tracefunc.borrow()); + return 0; + } + + inline BorrowedMainGreenlet borrow_main_greenlet() const + { + assert(this->main_greenlet); + assert(this->main_greenlet.REFCNT() >= 2); + return this->main_greenlet; + }; + + inline OwnedMainGreenlet get_main_greenlet() + { + return this->main_greenlet; + } + + /** + * In addition to returning a new reference to the currunt + * greenlet, this performs any maintenance needed. + */ + inline OwnedGreenlet get_current() + { + /* green_dealloc() cannot delete greenlets from other threads, so + it stores them in the thread dict; delete them now. */ + this->clear_deleteme_list(); + //assert(this->current_greenlet->main_greenlet == this->main_greenlet); + //assert(this->main_greenlet->main_greenlet == this->main_greenlet); + return this->current_greenlet; + } + + /** + * As for non-const get_current(); + */ + inline BorrowedGreenlet borrow_current() + { + this->clear_deleteme_list(); + return this->current_greenlet; + } + + /** + * Does no maintenance. + */ + inline OwnedGreenlet get_current() const + { + return this->current_greenlet; + } + + template + inline bool is_current(const refs::PyObjectPointer& obj) const + { + return this->current_greenlet.borrow_o() == obj.borrow_o(); + } + + inline void set_current(const OwnedGreenlet& target) + { + this->current_greenlet = target; + } + +private: + /** + * Deref and remove the greenlets from the deleteme list. Must be + * holding the GIL. + * + * If *murder* is true, then we must be called from a different + * thread than the one that these greenlets were running in. + * In that case, if the greenlet was actually running, we destroy + * the frame reference and otherwise make it appear dead before + * proceeding; otherwise, we would try (and fail) to raise an + * exception in it and wind up right back in this list. + */ + inline void clear_deleteme_list(const bool murder=false) + { + if (!this->deleteme.empty()) { + // It's possible we could add items to this list while + // running Python code if there's a thread switch, so we + // need to defensively copy it before that can happen. + deleteme_t copy = this->deleteme; + this->deleteme.clear(); // in case things come back on the list + for(deleteme_t::iterator it = copy.begin(), end = copy.end(); + it != end; + ++it ) { + PyGreenlet* to_del = *it; + if (murder) { + // Force each greenlet to appear dead; we can't raise an + // exception into it anymore anyway. + to_del->pimpl->murder_in_place(); + } + + // The only reference to these greenlets should be in + // this list, decreffing them should let them be + // deleted again, triggering calls to green_dealloc() + // in the correct thread (if we're not murdering). + // This may run arbitrary Python code and switch + // threads or greenlets! + Py_DECREF(to_del); + if (PyErr_Occurred()) { + PyErr_WriteUnraisable(nullptr); + PyErr_Clear(); + } + } + } + } + +public: + + /** + * Returns a new reference, or a false object. + */ + inline OwnedObject get_tracefunc() const + { + return tracefunc; + }; + + + inline void set_tracefunc(BorrowedObject tracefunc) + { + assert(tracefunc); + if (tracefunc == BorrowedObject(Py_None)) { + this->tracefunc.CLEAR(); + } + else { + this->tracefunc = tracefunc; + } + } + + /** + * Given a reference to a greenlet that some other thread + * attempted to delete (has a refcount of 0) store it for later + * deletion when the thread this state belongs to is current. + */ + inline void delete_when_thread_running(PyGreenlet* to_del) + { + Py_INCREF(to_del); + this->deleteme.push_back(to_del); + } + + /** + * Set to std::clock_t(-1) to disable. + */ + inline static std::clock_t& clocks_used_doing_gc() + { + return ThreadState::_clocks_used_doing_gc; + } + + ~ThreadState() + { + if (!PyInterpreterState_Head()) { + // We shouldn't get here (our callers protect us) + // but if we do, all we can do is bail early. + return; + } + + // We should not have an "origin" greenlet; that only exists + // for the temporary time during a switch, which should not + // be in progress as the thread dies. + //assert(!this->switching_state.origin); + + this->tracefunc.CLEAR(); + + // Forcibly GC as much as we can. + this->clear_deleteme_list(true); + + // The pending call did this. + assert(this->main_greenlet->thread_state() == nullptr); + + // If the main greenlet is the current greenlet, + // then we "fell off the end" and the thread died. + // It's possible that there is some other greenlet that + // switched to us, leaving a reference to the main greenlet + // on the stack, somewhere uncollectible. Try to detect that. + if (this->current_greenlet == this->main_greenlet && this->current_greenlet) { + assert(this->current_greenlet->is_currently_running_in_some_thread()); + // Drop one reference we hold. + this->current_greenlet.CLEAR(); + assert(!this->current_greenlet); + // Only our reference to the main greenlet should be left, + // But hold onto the pointer in case we need to do extra cleanup. + PyGreenlet* old_main_greenlet = this->main_greenlet.borrow(); + Py_ssize_t cnt = this->main_greenlet.REFCNT(); + this->main_greenlet.CLEAR(); + if (ThreadState::_clocks_used_doing_gc != std::clock_t(-1) + && cnt == 2 && Py_REFCNT(old_main_greenlet) == 1) { + // Highly likely that the reference is somewhere on + // the stack, not reachable by GC. Verify. + // XXX: This is O(n) in the total number of objects. + // TODO: Add a way to disable this at runtime, and + // another way to report on it. + std::clock_t begin = std::clock(); + NewReference gc(PyImport_ImportModule("gc")); + if (gc) { + OwnedObject get_referrers = gc.PyRequireAttr(ThreadState::get_referrers_name); + OwnedList refs(get_referrers.PyCall(old_main_greenlet)); + if (refs && refs.empty()) { + assert(refs.REFCNT() == 1); + // We found nothing! So we left a dangling + // reference: Probably the last thing some + // other greenlet did was call + // 'getcurrent().parent.switch()' to switch + // back to us. Clean it up. This will be the + // case on CPython 3.7 and newer, as they use + // an internal calling conversion that avoids + // creating method objects and storing them on + // the stack. + Py_DECREF(old_main_greenlet); + } + else if (refs + && refs.size() == 1 + && PyCFunction_Check(refs.at(0)) + && Py_REFCNT(refs.at(0)) == 2) { + assert(refs.REFCNT() == 1); + // Ok, we found a C method that refers to the + // main greenlet, and its only referenced + // twice, once in the list we just created, + // once from...somewhere else. If we can't + // find where else, then this is a leak. + // This happens in older versions of CPython + // that create a bound method object somewhere + // on the stack that we'll never get back to. + if (PyCFunction_GetFunction(refs.at(0).borrow()) == (PyCFunction)green_switch) { + BorrowedObject function_w = refs.at(0); + refs.clear(); // destroy the reference + // from the list. + // back to one reference. Can *it* be + // found? + assert(function_w.REFCNT() == 1); + refs = get_referrers.PyCall(function_w); + if (refs && refs.empty()) { + // Nope, it can't be found so it won't + // ever be GC'd. Drop it. + Py_CLEAR(function_w); + } + } + } + std::clock_t end = std::clock(); + ThreadState::_clocks_used_doing_gc += (end - begin); + } + } + } + + // We need to make sure this greenlet appears to be dead, + // because otherwise deallocing it would fail to raise an + // exception in it (the thread is dead) and put it back in our + // deleteme list. + if (this->current_greenlet) { + this->current_greenlet->murder_in_place(); + this->current_greenlet.CLEAR(); + } + + if (this->main_greenlet) { + // Couldn't have been the main greenlet that was running + // when the thread exited (because we already cleared this + // pointer if it was). This shouldn't be possible? + + // If the main greenlet was current when the thread died (it + // should be, right?) then we cleared its self pointer above + // when we cleared the current greenlet's main greenlet pointer. + // assert(this->main_greenlet->main_greenlet == this->main_greenlet + // || !this->main_greenlet->main_greenlet); + // // self reference, probably gone + // this->main_greenlet->main_greenlet.CLEAR(); + + // This will actually go away when the ivar is destructed. + this->main_greenlet.CLEAR(); + } + + if (PyErr_Occurred()) { + PyErr_WriteUnraisable(NULL); + PyErr_Clear(); + } + + } + +}; + +ImmortalString ThreadState::get_referrers_name(nullptr); +PythonAllocator ThreadState::allocator; +std::clock_t ThreadState::_clocks_used_doing_gc(0); + +template +class ThreadStateCreator +{ +private: + // Initialized to 1, and, if still 1, created on access. + // Set to 0 on destruction. + ThreadState* _state; + G_NO_COPIES_OF_CLS(ThreadStateCreator); +public: + + // Only one of these, auto created per thread + ThreadStateCreator() : + _state((ThreadState*)1) + { + } + + ~ThreadStateCreator() + { + ThreadState* tmp = this->_state; + this->_state = nullptr; + if (tmp && tmp != (ThreadState*)1) { + Destructor x(tmp); + } + } + + inline ThreadState& state() + { + // The main greenlet will own this pointer when it is created, + // which will be right after this. The plan is to give every + // greenlet a pointer to the main greenlet for the thread it + // runs in; if we are doing something cross-thread, we need to + // access the pointer from the main greenlet. Deleting the + // thread, and hence the thread-local storage, will delete the + // state pointer in the main greenlet. + if (this->_state == (ThreadState*)1) { + // XXX: Assuming allocation never fails + this->_state = new ThreadState; + // For non-standard threading, we need to store an object + // in the Python thread state dictionary so that it can be + // DECREF'd when the thread ends (ideally; the dict could + // last longer) and clean this object up. + } + if (!this->_state) { + throw std::runtime_error("Accessing state after destruction."); + } + return *this->_state; + } + + operator ThreadState&() + { + return this->state(); + } + + operator ThreadState*() + { + return &this->state(); + } + + inline int tp_traverse(visitproc visit, void* arg) + { + if (this->_state) { + return this->_state->tp_traverse(visit, arg); + } + return 0; + } + +}; + +#if G_USE_STANDARD_THREADING == 1 +// We can't use the PythonAllocator for this, because we push to it +// from the thread state destructor, which doesn't have the GIL, +// and Python's allocators can only be called with the GIL. +typedef std::vector cleanup_queue_t; +#else +class cleanup_queue_t { +public: + inline ssize_t size() const { return 0; }; + inline bool empty() const { return true; }; + inline void pop_back() + { + throw std::out_of_range("empty queue."); + }; + inline ThreadState* back() + { + throw std::out_of_range("empty queue."); + }; + inline void push_back(ThreadState* g) + { + throw std::out_of_range("empty queue."); + }; +}; +#endif +}; // namespace greenlet + +#endif diff --git a/.venv/Lib/site-packages/greenlet/greenlet_thread_state_dict_cleanup.hpp b/.venv/Lib/site-packages/greenlet/greenlet_thread_state_dict_cleanup.hpp new file mode 100644 index 000000000..acf39c8f4 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/greenlet_thread_state_dict_cleanup.hpp @@ -0,0 +1,118 @@ +#ifndef GREENLET_THREAD_STATE_DICT_CLEANUP_HPP +#define GREENLET_THREAD_STATE_DICT_CLEANUP_HPP + +#include "greenlet_internal.hpp" +#include "greenlet_thread_state.hpp" + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wmissing-field-initializers" +#endif + +#ifndef G_THREAD_STATE_DICT_CLEANUP_TYPE +// shut the compiler up if it looks at this file in isolation +#define ThreadStateCreator int +#endif + +// Define a Python object that goes in the Python thread state dict +// when the greenlet thread state is created, and which owns the +// reference to the greenlet thread local state. +// When the thread state dict is cleaned up, so too is the thread +// state. This works best if we make sure there are no circular +// references to the thread state. +typedef struct _PyGreenletCleanup { + PyObject_HEAD + ThreadStateCreator* thread_state_creator; +} PyGreenletCleanup; + +static void +cleanup_do_dealloc(PyGreenletCleanup* self) +{ + ThreadStateCreator* tmp = self->thread_state_creator; + self->thread_state_creator = nullptr; + if (tmp) { + delete tmp; + } +} + +static void +cleanup_dealloc(PyGreenletCleanup* self) +{ + PyObject_GC_UnTrack(self); + cleanup_do_dealloc(self); +} + +static int +cleanup_clear(PyGreenletCleanup* self) +{ + // This method is never called by our test cases. + cleanup_do_dealloc(self); + return 0; +} + +static int +cleanup_traverse(PyGreenletCleanup* self, visitproc visit, void* arg) +{ + if (self->thread_state_creator) { + return self->thread_state_creator->tp_traverse(visit, arg); + } + return 0; +} + +static int +cleanup_is_gc(PyGreenlet* UNUSED(self)) +{ + return 1; +} + +static PyTypeObject PyGreenletCleanup_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "greenlet._greenlet.ThreadStateCleanup", + sizeof(struct _PyGreenletCleanup), + 0, /* tp_itemsize */ + /* methods */ + (destructor)cleanup_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as _number*/ + 0, /* tp_as _sequence*/ + 0, /* tp_as _mapping*/ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer*/ + G_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "Internal use only", /* tp_doc */ + (traverseproc)cleanup_traverse, /* tp_traverse */ + (inquiry)cleanup_clear, /* tp_clear */ + 0, /* tp_richcompare */ + // XXX: Don't our flags promise a weakref? + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ + PyObject_GC_Del, /* tp_free */ + (inquiry)cleanup_is_gc, /* tp_is_gc */ +}; + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + + +#endif diff --git a/.venv/Lib/site-packages/greenlet/greenlet_thread_support.hpp b/.venv/Lib/site-packages/greenlet/greenlet_thread_support.hpp new file mode 100644 index 000000000..747ae4773 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/greenlet_thread_support.hpp @@ -0,0 +1,144 @@ +#ifndef GREENLET_THREAD_SUPPORT_HPP +#define GREENLET_THREAD_SUPPORT_HPP + +/** + * Defines various utility functions to help greenlet integrate well + * with threads. When possible, we use portable C++ 11 threading; when + * not possible, we will use platform specific APIs if needed and + * available. (Currently, this is only for Python 2.7 on Windows.) + */ + +#include +#include "greenlet_compiler_compat.hpp" + +// Allow setting this to 0 on the command line so that we +// can test these code paths on compilers that otherwise support +// standard threads. +#ifndef G_USE_STANDARD_THREADING +#if __cplusplus >= 201103 +// Cool. We should have standard support +# define G_USE_STANDARD_THREADING 1 +#elif defined(_MSC_VER) +// MSVC doesn't use a modern version of __cplusplus automatically, you +// have to opt-in to update it with /Zc:__cplusplus, but that's not +// available on our old version of visual studio for Python 2.7 +# if _MSC_VER <= 1500 +// Python 2.7 on Windows. Use the Python thread state and native Win32 APIs. +# define G_USE_STANDARD_THREADING 0 +# else +// Assume we have a compiler that supports it. The Appveyor compilers +// we use all do have standard support +# define G_USE_STANDARD_THREADING 1 +# endif +#elif defined(__GNUC__) || defined(__clang__) +// All tested versions either do, or can with the right --std argument, support what we need +# define G_USE_STANDARD_THREADING 1 +#else +# define G_USE_STANDARD_THREADING 0 +#endif +#endif /* G_USE_STANDARD_THREADING */ + +namespace greenlet { + class LockInitError : public std::runtime_error + { + public: + LockInitError(const char* what) : std::runtime_error(what) + {}; + }; +}; + + +#if G_USE_STANDARD_THREADING == 1 +# define G_THREAD_LOCAL_SUPPORTS_DESTRUCTOR 1 +# include +# include +# define G_THREAD_LOCAL_VAR thread_local +namespace greenlet { + typedef std::mutex Mutex; + typedef std::lock_guard LockGuard; +}; +#else +// NOTE: At this writing, the mutex isn't currently required; +// we don't use a shared cleanup queue or Py_AddPendingCall in this +// model, we rely on the thread state dictionary for cleanup. +# if defined(_MSC_VER) +// We should only hit this case for Python 2.7 on Windows. +# define G_THREAD_LOCAL_VAR __declspec(thread) +# include +namespace greenlet { + class Mutex + { + CRITICAL_SECTION _mutex; + G_NO_COPIES_OF_CLS(Mutex); + public: + Mutex() + { + InitializeCriticalSection(&this->_mutex); + }; + + void Lock() + { + EnterCriticalSection(&this->_mutex); + }; + + void UnLock() + { + LeaveCriticalSection(&this->_mutex); + }; + }; +}; +# elif (defined(__GNUC__) || defined(__clang__)) || (defined(__SUNPRO_C)) +// GCC, clang, SunStudio all use __thread for thread-local variables. +// For locks, we can use PyThread APIs, officially added in 3.2, but +// present back to 2.7 +# define G_THREAD_LOCAL_VAR __thread +# include "pythread.h" +namespace greenlet { + class Mutex + { + PyThread_type_lock _mutex; + G_NO_COPIES_OF_CLS(Mutex); + public: + Mutex() + { + this->_mutex = PyThread_allocate_lock(); + if (!this->_mutex) { + throw LockInitError("Failed to initialize mutex."); + } + }; + + void Lock() + { + PyThread_acquire_lock(this->_mutex, WAIT_LOCK); + }; + + void UnLock() + { + PyThread_release_lock(this->_mutex); + }; + }; +}; +# else +# error Unable to declare thread-local variables. +# endif +// the RAII lock keeper for all non-standard threading platforms. +namespace greenlet { + class LockGuard + { + Mutex& _mutex; + G_NO_COPIES_OF_CLS(LockGuard); + public: + LockGuard(Mutex& m) : _mutex(m) + { + this->_mutex.Lock(); + }; + ~LockGuard() + { + this->_mutex.UnLock(); + }; + }; + +}; +#endif /* G_USE_STANDARD_THREADING == 1 */ + +#endif /* GREENLET_THREAD_SUPPORT_HPP */ diff --git a/.venv/Lib/site-packages/greenlet/platform/__init__.py b/.venv/Lib/site-packages/greenlet/platform/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/.venv/Lib/site-packages/greenlet/platform/__pycache__/__init__.cpython-311.pyc b/.venv/Lib/site-packages/greenlet/platform/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..813b10265e7d3cffd31e0445982ae14e0ffacd71 GIT binary patch literal 212 zcmZ3^%ge<81kaZwq=4whAOZ#$p^VRLK*n^26oz01O-8?!3`I;p{%4TnuXJatn9$*^rF<%yqwe${eqmtlC=DyT>bd?%)HE!_;|g7%3mBdx%nxj eIjMF + * Add support for strange GCC caller-save decisions + * (ported from switch_aarch64_gcc.h) + * 18-Aug-11 Alexey Borzenkov + * Correctly save rbp, csr and cw + * 01-Apr-04 Hye-Shik Chang + * Ported from i386 to amd64. + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for spark + * 31-Avr-02 Armin Rigo + * Added ebx, esi and edi register-saves. + * 01-Mar-02 Samual M. Rushing + * Ported from i386. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +/* #define STACK_MAGIC 3 */ +/* the above works fine with gcc 2.96, but 2.95.3 wants this */ +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "r12", "r13", "r14", "r15" + +static int +slp_switch(void) +{ + int err; + void* rbp; + void* rbx; + unsigned int csr; + unsigned short cw; + /* This used to be declared 'register', but that does nothing in + modern compilers and is explicitly forbidden in some new + standards. */ + long *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("fstcw %0" : "=m" (cw)); + __asm__ volatile ("stmxcsr %0" : "=m" (csr)); + __asm__ volatile ("movq %%rbp, %0" : "=m" (rbp)); + __asm__ volatile ("movq %%rbx, %0" : "=m" (rbx)); + __asm__ ("movq %%rsp, %0" : "=g" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "addq %0, %%rsp\n" + "addq %0, %%rbp\n" + : + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + __asm__ volatile ("xorq %%rax, %%rax" : "=a" (err)); + } + __asm__ volatile ("movq %0, %%rbx" : : "m" (rbx)); + __asm__ volatile ("movq %0, %%rbp" : : "m" (rbp)); + __asm__ volatile ("ldmxcsr %0" : : "m" (csr)); + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("" : : : REGS_TO_SAVE); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_arm32_gcc.h b/.venv/Lib/site-packages/greenlet/platform/switch_arm32_gcc.h new file mode 100644 index 000000000..035d6b949 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_arm32_gcc.h @@ -0,0 +1,79 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 14-Aug-06 File creation. Ported from Arm Thumb. Sylvain Baro + * 3-Sep-06 Commented out saving of r1-r3 (r4 already commented out) as I + * read that these do not need to be saved. Also added notes and + * errors related to the frame pointer. Richard Tew. + * + * NOTES + * + * It is not possible to detect if fp is used or not, so the supplied + * switch function needs to support it, so that you can remove it if + * it does not apply to you. + * + * POSSIBLE ERRORS + * + * "fp cannot be used in asm here" + * + * - Try commenting out "fp" in REGS_TO_SAVE. + * + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL +#define STACK_MAGIC 0 +#define REG_SP "sp" +#define REG_SPSP "sp,sp" +#ifdef __thumb__ +#define REG_FP "r7" +#define REG_FPFP "r7,r7" +#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r8", "r9", "r10", "r11", "lr" +#else +#define REG_FP "fp" +#define REG_FPFP "fp,fp" +#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r7", "r8", "r9", "r10", "lr" +#endif +#if defined(__SOFTFP__) +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL +#elif defined(__VFP_FP__) +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "d8", "d9", "d10", "d11", \ + "d12", "d13", "d14", "d15" +#elif defined(__MAVERICK__) +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "mvf4", "mvf5", "mvf6", "mvf7", \ + "mvf8", "mvf9", "mvf10", "mvf11", \ + "mvf12", "mvf13", "mvf14", "mvf15" +#else +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "f4", "f5", "f6", "f7" +#endif + +static int +#ifdef __GNUC__ +__attribute__((optimize("no-omit-frame-pointer"))) +#endif +slp_switch(void) +{ + void *fp; + register int *stackref, stsizediff; + int result; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("mov r0," REG_FP "\n\tstr r0,%0" : "=m" (fp) : : "r0"); + __asm__ ("mov %0," REG_SP : "=r" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "add " REG_SPSP ",%0\n" + "add " REG_FPFP ",%0\n" + : + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("ldr r0,%1\n\tmov " REG_FP ",r0\n\tmov %0, #0" : "=r" (result) : "m" (fp) : "r0"); + __asm__ volatile ("" : : : REGS_TO_SAVE); + return result; +} + +#endif diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_arm32_ios.h b/.venv/Lib/site-packages/greenlet/platform/switch_arm32_ios.h new file mode 100644 index 000000000..e993707f5 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_arm32_ios.h @@ -0,0 +1,67 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 31-May-15 iOS support. Ported from arm32. Proton + * + * NOTES + * + * It is not possible to detect if fp is used or not, so the supplied + * switch function needs to support it, so that you can remove it if + * it does not apply to you. + * + * POSSIBLE ERRORS + * + * "fp cannot be used in asm here" + * + * - Try commenting out "fp" in REGS_TO_SAVE. + * + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 0 +#define REG_SP "sp" +#define REG_SPSP "sp,sp" +#define REG_FP "r7" +#define REG_FPFP "r7,r7" +#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r8", "r10", "r11", "lr" +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "d8", "d9", "d10", "d11", \ + "d12", "d13", "d14", "d15" + +static int +#ifdef __GNUC__ +__attribute__((optimize("no-omit-frame-pointer"))) +#endif +slp_switch(void) +{ + void *fp; + register int *stackref, stsizediff, result; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("str " REG_FP ",%0" : "=m" (fp)); + __asm__ ("mov %0," REG_SP : "=r" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "add " REG_SPSP ",%0\n" + "add " REG_FPFP ",%0\n" + : + : "r" (stsizediff) + : REGS_TO_SAVE /* Clobber registers, force compiler to + * recalculate address of void *fp from REG_SP or REG_FP */ + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ( + "ldr " REG_FP ", %1\n\t" + "mov %0, #0" + : "=r" (result) + : "m" (fp) + : REGS_TO_SAVE /* Force compiler to restore saved registers after this */ + ); + return result; +} + +#endif diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_arm64_masm.asm b/.venv/Lib/site-packages/greenlet/platform/switch_arm64_masm.asm new file mode 100644 index 000000000..29f9c225e --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_arm64_masm.asm @@ -0,0 +1,53 @@ + AREA switch_arm64_masm, CODE, READONLY; + GLOBAL slp_switch [FUNC] + EXTERN slp_save_state_asm + EXTERN slp_restore_state_asm + +slp_switch + ; push callee saved registers to stack + stp x19, x20, [sp, #-16]! + stp x21, x22, [sp, #-16]! + stp x23, x24, [sp, #-16]! + stp x25, x26, [sp, #-16]! + stp x27, x28, [sp, #-16]! + stp x29, x30, [sp, #-16]! + stp d8, d9, [sp, #-16]! + stp d10, d11, [sp, #-16]! + stp d12, d13, [sp, #-16]! + stp d14, d15, [sp, #-16]! + + ; call slp_save_state_asm with stack pointer + mov x0, sp + bl slp_save_state_asm + + ; early return for return value of 1 and -1 + cmp x0, #-1 + b.eq RETURN + cmp x0, #1 + b.eq RETURN + + ; increment stack and frame pointer + add sp, sp, x0 + add x29, x29, x0 + + bl slp_restore_state_asm + + ; store return value for successful completion of routine + mov x0, #0 + +RETURN + ; pop registers from stack + ldp d14, d15, [sp], #16 + ldp d12, d13, [sp], #16 + ldp d10, d11, [sp], #16 + ldp d8, d9, [sp], #16 + ldp x29, x30, [sp], #16 + ldp x27, x28, [sp], #16 + ldp x25, x26, [sp], #16 + ldp x23, x24, [sp], #16 + ldp x21, x22, [sp], #16 + ldp x19, x20, [sp], #16 + + ret + + END diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_arm64_masm.obj b/.venv/Lib/site-packages/greenlet/platform/switch_arm64_masm.obj new file mode 100644 index 0000000000000000000000000000000000000000..f6f220e4310baaa9756110685ce7d6a2bdf90c37 GIT binary patch literal 746 zcma)4PiqrF6n~qoo~*PNZ{i+=wji4b#Xu2~wiJpGk)*AMF07NyB(9n1#+i+!)I;v| zBKQG3?t1eB$T(lYgGb4+lu{_QmQrebldQB_4?cMF-uu0IZ{DA2e8@rZ+e^~30488W z`B{KPh%yV{HEIpyeum^wI#7P*HfX)ux?9U&c!SFK-$o|OFtKn{Q|a-#N>2inp0-tb zCRKXAtg2SolaoLv$Ll&ds_Epj?SH+8K{t?XSjKaFsEy%yh}=V70BaHj zEY5kWk_zcJo{$SSUL~=K(zW|tnhm$rA z<%dZ$q?>RX*18r{!azhaYR1lVb;g;mR-6h!#F>|p@;aje%0a|CZrE7s+SXuT>MS=Y ziQPiMY-5DD&5+S7^H03fy7qt7ir}L34kK|h68s-MU>{lXOqlr?!Y=`~WwviNenFS_ zZalVSHh-0FU4lj#X8u5`ODn6@#{f?dHE&%XdP~_I3;$RS9-(z*>>ydkm*f@oWlUn~ Qn+^;lsEi}=H#!Q3U&UU-WdHyG literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_arm64_msvc.h b/.venv/Lib/site-packages/greenlet/platform/switch_arm64_msvc.h new file mode 100644 index 000000000..7ab7f45be --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_arm64_msvc.h @@ -0,0 +1,17 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 21-Oct-21 Niyas Sait + * First version to enable win/arm64 support. + */ + +#define STACK_REFPLUS 1 +#define STACK_MAGIC 0 + +/* Use the generic support for an external assembly language slp_switch function. */ +#define EXTERNAL_ASM + +#ifdef SLP_EVAL +/* This always uses the external masm assembly file. */ +#endif \ No newline at end of file diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_csky_gcc.h b/.venv/Lib/site-packages/greenlet/platform/switch_csky_gcc.h new file mode 100644 index 000000000..7486b948b --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_csky_gcc.h @@ -0,0 +1,48 @@ +#ifdef SLP_EVAL +#define STACK_MAGIC 0 +#define REG_FP "r8" +#ifdef __CSKYABIV2__ +#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r7", "r9", "r10", "r11", "r15",\ + "r16", "r17", "r18", "r19", "r20", "r21", "r22",\ + "r23", "r24", "r25" + +#if defined (__CSKY_HARD_FLOAT__) || (__CSKY_VDSP__) +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "vr8", "vr9", "vr10", "vr11", "vr12",\ + "vr13", "vr14", "vr15" +#else +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL +#endif +#else +#define REGS_TO_SAVE "r9", "r10", "r11", "r12", "r13", "r15" +#endif + + +static int +#ifdef __GNUC__ +__attribute__((optimize("no-omit-frame-pointer"))) +#endif +slp_switch(void) +{ + register int *stackref, stsizediff; + int result; + + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ ("mov %0, sp" : "=r" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "addu sp,%0\n" + "addu "REG_FP",%0\n" + : + : "r" (stsizediff) + ); + + SLP_RESTORE_STATE(); + } + __asm__ volatile ("movi %0, 0" : "=r" (result)); + __asm__ volatile ("" : : : REGS_TO_SAVE); + + return result; +} + +#endif diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_m68k_gcc.h b/.venv/Lib/site-packages/greenlet/platform/switch_m68k_gcc.h new file mode 100644 index 000000000..da761c2da --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_m68k_gcc.h @@ -0,0 +1,38 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 2014-01-06 Andreas Schwab + * File created. + */ + +#ifdef SLP_EVAL + +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a2", "%a3", "%a4" + +static int +slp_switch(void) +{ + int err; + int *stackref, stsizediff; + void *fp, *a5; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("move.l %%fp, %0" : "=m"(fp)); + __asm__ volatile ("move.l %%a5, %0" : "=m"(a5)); + __asm__ ("move.l %%sp, %0" : "=r"(stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ("add.l %0, %%sp; add.l %0, %%fp" : : "r"(stsizediff)); + SLP_RESTORE_STATE(); + __asm__ volatile ("clr.l %0" : "=g" (err)); + } + __asm__ volatile ("move.l %0, %%a5" : : "m"(a5)); + __asm__ volatile ("move.l %0, %%fp" : : "m"(fp)); + __asm__ volatile ("" : : : REGS_TO_SAVE); + return err; +} + +#endif diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_mips_unix.h b/.venv/Lib/site-packages/greenlet/platform/switch_mips_unix.h new file mode 100644 index 000000000..1916b264d --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_mips_unix.h @@ -0,0 +1,64 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 20-Sep-14 Matt Madison + * Re-code the saving of the gp register for MIPS64. + * 05-Jan-08 Thiemo Seufer + * Ported from ppc. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "$16", "$17", "$18", "$19", "$20", "$21", "$22", \ + "$23", "$30" +static int +slp_switch(void) +{ + register int err; + register int *stackref, stsizediff; +#ifdef __mips64 + uint64_t gpsave; +#endif + __asm__ __volatile__ ("" : : : REGS_TO_SAVE); +#ifdef __mips64 + __asm__ __volatile__ ("sd $28,%0" : "=m" (gpsave) : : ); +#endif + __asm__ ("move %0, $29" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ __volatile__ ( +#ifdef __mips64 + "daddu $29, %0\n" +#else + "addu $29, %0\n" +#endif + : /* no outputs */ + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } +#ifdef __mips64 + __asm__ __volatile__ ("ld $28,%0" : : "m" (gpsave) : ); +#endif + __asm__ __volatile__ ("" : : : REGS_TO_SAVE); + __asm__ __volatile__ ("move %0, $0" : "=r" (err)); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_ppc64_aix.h b/.venv/Lib/site-packages/greenlet/platform/switch_ppc64_aix.h new file mode 100644 index 000000000..e07b8de3d --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_ppc64_aix.h @@ -0,0 +1,103 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 16-Oct-20 Jesse Gorzinski + * Copied from Linux PPC64 implementation + * 04-Sep-18 Alexey Borzenkov + * Workaround a gcc bug using manual save/restore of r30 + * 21-Mar-18 Tulio Magno Quites Machado Filho + * Added r30 to the list of saved registers in order to fully comply with + * both ppc64 ELFv1 ABI and the ppc64le ELFv2 ABI, that classify this + * register as a nonvolatile register used for local variables. + * 21-Mar-18 Laszlo Boszormenyi + * Save r2 (TOC pointer) manually. + * 10-Dec-13 Ulrich Weigand + * Support ELFv2 ABI. Save float/vector registers. + * 09-Mar-12 Michael Ellerman + * 64-bit implementation, copied from 32-bit. + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 14-Jan-04 Bob Ippolito + * added cr2-cr4 to the registers to be saved. + * Open questions: Should we save FP registers? + * What about vector registers? + * Differences between darwin and unix? + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 04-Oct-02 Gustavo Niemeyer + * Ported from MacOS version. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 29-Jun-02 Christian Tismer + * Added register 13-29, 31 saves. The same way as + * Armin Rigo did for the x86_unix version. + * This seems to be now fully functional! + * 04-Mar-02 Hye-Shik Chang + * Ported from i386. + * 31-Jul-12 Trevor Bowen + * Changed memory constraints to register only. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 6 + +#if defined(__ALTIVEC__) +#define ALTIVEC_REGS \ + "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", \ + "v28", "v29", "v30", "v31", +#else +#define ALTIVEC_REGS +#endif + +#define REGS_TO_SAVE "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "r31", \ + "fr14", "fr15", "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", \ + "fr22", "fr23", "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", \ + "fr30", "fr31", \ + ALTIVEC_REGS \ + "cr2", "cr3", "cr4" + +static int +slp_switch(void) +{ + register int err; + register long *stackref, stsizediff; + void * toc; + void * r30; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("std 2, %0" : "=m" (toc)); + __asm__ volatile ("std 30, %0" : "=m" (r30)); + __asm__ ("mr %0, 1" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "mr 11, %0\n" + "add 1, 1, 11\n" + : /* no outputs */ + : "r" (stsizediff) + : "11" + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("ld 30, %0" : : "m" (r30)); + __asm__ volatile ("ld 2, %0" : : "m" (toc)); + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("li %0, 0" : "=r" (err)); + return err; +} + +#endif diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_ppc64_linux.h b/.venv/Lib/site-packages/greenlet/platform/switch_ppc64_linux.h new file mode 100644 index 000000000..88e6847fb --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_ppc64_linux.h @@ -0,0 +1,105 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 04-Sep-18 Alexey Borzenkov + * Workaround a gcc bug using manual save/restore of r30 + * 21-Mar-18 Tulio Magno Quites Machado Filho + * Added r30 to the list of saved registers in order to fully comply with + * both ppc64 ELFv1 ABI and the ppc64le ELFv2 ABI, that classify this + * register as a nonvolatile register used for local variables. + * 21-Mar-18 Laszlo Boszormenyi + * Save r2 (TOC pointer) manually. + * 10-Dec-13 Ulrich Weigand + * Support ELFv2 ABI. Save float/vector registers. + * 09-Mar-12 Michael Ellerman + * 64-bit implementation, copied from 32-bit. + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 14-Jan-04 Bob Ippolito + * added cr2-cr4 to the registers to be saved. + * Open questions: Should we save FP registers? + * What about vector registers? + * Differences between darwin and unix? + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 04-Oct-02 Gustavo Niemeyer + * Ported from MacOS version. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 29-Jun-02 Christian Tismer + * Added register 13-29, 31 saves. The same way as + * Armin Rigo did for the x86_unix version. + * This seems to be now fully functional! + * 04-Mar-02 Hye-Shik Chang + * Ported from i386. + * 31-Jul-12 Trevor Bowen + * Changed memory constraints to register only. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#if _CALL_ELF == 2 +#define STACK_MAGIC 4 +#else +#define STACK_MAGIC 6 +#endif + +#if defined(__ALTIVEC__) +#define ALTIVEC_REGS \ + "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", \ + "v28", "v29", "v30", "v31", +#else +#define ALTIVEC_REGS +#endif + +#define REGS_TO_SAVE "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "r31", \ + "fr14", "fr15", "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", \ + "fr22", "fr23", "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", \ + "fr30", "fr31", \ + ALTIVEC_REGS \ + "cr2", "cr3", "cr4" + +static int +slp_switch(void) +{ + register int err; + register long *stackref, stsizediff; + void * toc; + void * r30; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("std 2, %0" : "=m" (toc)); + __asm__ volatile ("std 30, %0" : "=m" (r30)); + __asm__ ("mr %0, 1" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "mr 11, %0\n" + "add 1, 1, 11\n" + : /* no outputs */ + : "r" (stsizediff) + : "11" + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("ld 30, %0" : : "m" (r30)); + __asm__ volatile ("ld 2, %0" : : "m" (toc)); + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("li %0, 0" : "=r" (err)); + return err; +} + +#endif diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_ppc_aix.h b/.venv/Lib/site-packages/greenlet/platform/switch_ppc_aix.h new file mode 100644 index 000000000..c7d476f67 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_ppc_aix.h @@ -0,0 +1,87 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 07-Mar-11 Floris Bruynooghe + * Do not add stsizediff to general purpose + * register (GPR) 30 as this is a non-volatile and + * unused by the PowerOpen Environment, therefore + * this was modifying a user register instead of the + * frame pointer (which does not seem to exist). + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 14-Jan-04 Bob Ippolito + * added cr2-cr4 to the registers to be saved. + * Open questions: Should we save FP registers? + * What about vector registers? + * Differences between darwin and unix? + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 04-Oct-02 Gustavo Niemeyer + * Ported from MacOS version. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 29-Jun-02 Christian Tismer + * Added register 13-29, 31 saves. The same way as + * Armin Rigo did for the x86_unix version. + * This seems to be now fully functional! + * 04-Mar-02 Hye-Shik Chang + * Ported from i386. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 3 + +/* !!!!WARNING!!!! need to add "r31" in the next line if this header file + * is meant to be compiled non-dynamically! + */ +#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "cr2", "cr3", "cr4" +static int +slp_switch(void) +{ + register int err; + register int *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ ("mr %0, 1" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "mr 11, %0\n" + "add 1, 1, 11\n" + : /* no outputs */ + : "r" (stsizediff) + : "11" + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("li %0, 0" : "=r" (err)); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_ppc_linux.h b/.venv/Lib/site-packages/greenlet/platform/switch_ppc_linux.h new file mode 100644 index 000000000..0a7125545 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_ppc_linux.h @@ -0,0 +1,84 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 14-Jan-04 Bob Ippolito + * added cr2-cr4 to the registers to be saved. + * Open questions: Should we save FP registers? + * What about vector registers? + * Differences between darwin and unix? + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 04-Oct-02 Gustavo Niemeyer + * Ported from MacOS version. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 29-Jun-02 Christian Tismer + * Added register 13-29, 31 saves. The same way as + * Armin Rigo did for the x86_unix version. + * This seems to be now fully functional! + * 04-Mar-02 Hye-Shik Chang + * Ported from i386. + * 31-Jul-12 Trevor Bowen + * Changed memory constraints to register only. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 3 + +/* !!!!WARNING!!!! need to add "r31" in the next line if this header file + * is meant to be compiled non-dynamically! + */ +#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "cr2", "cr3", "cr4" +static int +slp_switch(void) +{ + register int err; + register int *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ ("mr %0, 1" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "mr 11, %0\n" + "add 1, 1, 11\n" + "add 30, 30, 11\n" + : /* no outputs */ + : "r" (stsizediff) + : "11" + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("li %0, 0" : "=r" (err)); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_ppc_macosx.h b/.venv/Lib/site-packages/greenlet/platform/switch_ppc_macosx.h new file mode 100644 index 000000000..56e573fee --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_ppc_macosx.h @@ -0,0 +1,82 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 14-Jan-04 Bob Ippolito + * added cr2-cr4 to the registers to be saved. + * Open questions: Should we save FP registers? + * What about vector registers? + * Differences between darwin and unix? + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 29-Jun-02 Christian Tismer + * Added register 13-29, 31 saves. The same way as + * Armin Rigo did for the x86_unix version. + * This seems to be now fully functional! + * 04-Mar-02 Hye-Shik Chang + * Ported from i386. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 3 + +/* !!!!WARNING!!!! need to add "r31" in the next line if this header file + * is meant to be compiled non-dynamically! + */ +#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "cr2", "cr3", "cr4" + +static int +slp_switch(void) +{ + register int err; + register int *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ ("; asm block 2\n\tmr %0, r1" : "=g" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "; asm block 3\n" + "\tmr r11, %0\n" + "\tadd r1, r1, r11\n" + "\tadd r30, r30, r11\n" + : /* no outputs */ + : "g" (stsizediff) + : "r11" + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("li %0, 0" : "=r" (err)); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_ppc_unix.h b/.venv/Lib/site-packages/greenlet/platform/switch_ppc_unix.h new file mode 100644 index 000000000..2b3d307a2 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_ppc_unix.h @@ -0,0 +1,82 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 14-Jan-04 Bob Ippolito + * added cr2-cr4 to the registers to be saved. + * Open questions: Should we save FP registers? + * What about vector registers? + * Differences between darwin and unix? + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 04-Oct-02 Gustavo Niemeyer + * Ported from MacOS version. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 29-Jun-02 Christian Tismer + * Added register 13-29, 31 saves. The same way as + * Armin Rigo did for the x86_unix version. + * This seems to be now fully functional! + * 04-Mar-02 Hye-Shik Chang + * Ported from i386. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 3 + +/* !!!!WARNING!!!! need to add "r31" in the next line if this header file + * is meant to be compiled non-dynamically! + */ +#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "cr2", "cr3", "cr4" +static int +slp_switch(void) +{ + register int err; + register int *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ ("mr %0, 1" : "=g" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "mr 11, %0\n" + "add 1, 1, 11\n" + "add 30, 30, 11\n" + : /* no outputs */ + : "g" (stsizediff) + : "11" + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("li %0, 0" : "=r" (err)); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_riscv_unix.h b/.venv/Lib/site-packages/greenlet/platform/switch_riscv_unix.h new file mode 100644 index 000000000..24df9dbbe --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_riscv_unix.h @@ -0,0 +1,32 @@ +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "s0", "s1", "s2", "s3", "s4", "s5", \ + "s6", "s7", "s8", "s9", "s10", "s11", "fs0", "fs1", \ + "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", "fs8", "fs9", \ + "fs10", "fs11" + +static int +slp_switch(void) +{ + int ret; + long *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("mv %0, sp" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "add sp, sp, %0\n\t" + : /* no outputs */ + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("mv %0, zero" : "=r" (ret) : ); + return ret; +} + +#endif diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_s390_unix.h b/.venv/Lib/site-packages/greenlet/platform/switch_s390_unix.h new file mode 100644 index 000000000..6641854e6 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_s390_unix.h @@ -0,0 +1,87 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 25-Jan-12 Alexey Borzenkov + * Fixed Linux/S390 port to work correctly with + * different optimization options both on 31-bit + * and 64-bit. Thanks to Stefan Raabe for lots + * of testing. + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 06-Oct-02 Gustavo Niemeyer + * Ported to Linux/S390. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#ifdef __s390x__ +#define STACK_MAGIC 20 /* 20 * 8 = 160 bytes of function call area */ +#else +#define STACK_MAGIC 24 /* 24 * 4 = 96 bytes of function call area */ +#endif + +/* Technically, r11-r13 also need saving, but function prolog starts + with stm(g) and since there are so many saved registers already + it won't be optimized, resulting in all r6-r15 being saved */ +#define REGS_TO_SAVE "r6", "r7", "r8", "r9", "r10", "r14", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15" + +static int +slp_switch(void) +{ + register int ret; + register long *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); +#ifdef __s390x__ + __asm__ volatile ("lgr %0, 15" : "=r" (stackref) : ); +#else + __asm__ volatile ("lr %0, 15" : "=r" (stackref) : ); +#endif + { + SLP_SAVE_STATE(stackref, stsizediff); +/* N.B. + r11 may be used as the frame pointer, and in that case it cannot be + clobbered and needs offsetting just like the stack pointer (but in cases + where frame pointer isn't used we might clobber it accidentally). What's + scary is that r11 is 2nd (and even 1st when GOT is used) callee saved + register that gcc would chose for surviving function calls. However, + since r6-r10 are clobbered above, their cost for reuse is reduced, so + gcc IRA will chose them over r11 (not seeing r11 is implicitly saved), + making it relatively safe to offset in all cases. :) */ + __asm__ volatile ( +#ifdef __s390x__ + "agr 15, %0\n\t" + "agr 11, %0" +#else + "ar 15, %0\n\t" + "ar 11, %0" +#endif + : /* no outputs */ + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("lhi %0, 0" : "=r" (ret) : ); + return ret; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_sparc_sun_gcc.h b/.venv/Lib/site-packages/greenlet/platform/switch_sparc_sun_gcc.h new file mode 100644 index 000000000..652b57fdd --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_sparc_sun_gcc.h @@ -0,0 +1,92 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 16-May-15 Alexey Borzenkov + * Move stack spilling code inside save/restore functions + * 30-Aug-13 Floris Bruynooghe + Clean the register windows again before returning. + This does not clobber the PIC register as it leaves + the current window intact and is required for multi- + threaded code to work correctly. + * 08-Mar-11 Floris Bruynooghe + * No need to set return value register explicitly + * before the stack and framepointer are adjusted + * as none of the other registers are influenced by + * this. Also don't needlessly clean the windows + * ('ta %0" :: "i" (ST_CLEAN_WINDOWS)') as that + * clobbers the gcc PIC register (%l7). + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * added support for SunOS sparc with gcc + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + + +#define STACK_MAGIC 0 + + +#if defined(__sparcv9) +#define SLP_FLUSHW __asm__ volatile ("flushw") +#else +#define SLP_FLUSHW __asm__ volatile ("ta 3") /* ST_FLUSH_WINDOWS */ +#endif + +/* On sparc we need to spill register windows inside save/restore functions */ +#define SLP_BEFORE_SAVE_STATE() SLP_FLUSHW +#define SLP_BEFORE_RESTORE_STATE() SLP_FLUSHW + + +static int +slp_switch(void) +{ + register int err; + register int *stackref, stsizediff; + + /* Put current stack pointer into stackref. + * Register spilling is done in save/restore. + */ + __asm__ volatile ("mov %%sp, %0" : "=r" (stackref)); + + { + /* Thou shalt put SLP_SAVE_STATE into a local block */ + /* Copy the current stack onto the heap */ + SLP_SAVE_STATE(stackref, stsizediff); + + /* Increment stack and frame pointer by stsizediff */ + __asm__ volatile ( + "add %0, %%sp, %%sp\n\t" + "add %0, %%fp, %%fp" + : : "r" (stsizediff)); + + /* Copy new stack from it's save store on the heap */ + SLP_RESTORE_STATE(); + + __asm__ volatile ("mov %1, %0" : "=r" (err) : "i" (0)); + return err; + } +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_x32_unix.h b/.venv/Lib/site-packages/greenlet/platform/switch_x32_unix.h new file mode 100644 index 000000000..cb14ec1cf --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_x32_unix.h @@ -0,0 +1,63 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 17-Aug-12 Fantix King + * Ported from amd64. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "r12", "r13", "r14", "r15" + + +static int +slp_switch(void) +{ + void* ebp; + void* ebx; + unsigned int csr; + unsigned short cw; + register int err; + register int *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("fstcw %0" : "=m" (cw)); + __asm__ volatile ("stmxcsr %0" : "=m" (csr)); + __asm__ volatile ("movl %%ebp, %0" : "=m" (ebp)); + __asm__ volatile ("movl %%ebx, %0" : "=m" (ebx)); + __asm__ ("movl %%esp, %0" : "=g" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "addl %0, %%esp\n" + "addl %0, %%ebp\n" + : + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("movl %0, %%ebx" : : "m" (ebx)); + __asm__ volatile ("movl %0, %%ebp" : : "m" (ebp)); + __asm__ volatile ("ldmxcsr %0" : : "m" (csr)); + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("xorl %%eax, %%eax" : "=a" (err)); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_x64_masm.asm b/.venv/Lib/site-packages/greenlet/platform/switch_x64_masm.asm new file mode 100644 index 000000000..f5c72a27d --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_x64_masm.asm @@ -0,0 +1,111 @@ +; +; stack switching code for MASM on x641 +; Kristjan Valur Jonsson, sept 2005 +; + + +;prototypes for our calls +slp_save_state_asm PROTO +slp_restore_state_asm PROTO + + +pushxmm MACRO reg + sub rsp, 16 + .allocstack 16 + movaps [rsp], reg ; faster than movups, but we must be aligned + ; .savexmm128 reg, offset (don't know what offset is, no documentation) +ENDM +popxmm MACRO reg + movaps reg, [rsp] ; faster than movups, but we must be aligned + add rsp, 16 +ENDM + +pushreg MACRO reg + push reg + .pushreg reg +ENDM +popreg MACRO reg + pop reg +ENDM + + +.code +slp_switch PROC FRAME + ;realign stack to 16 bytes after return address push, makes the following faster + sub rsp,8 + .allocstack 8 + + pushxmm xmm15 + pushxmm xmm14 + pushxmm xmm13 + pushxmm xmm12 + pushxmm xmm11 + pushxmm xmm10 + pushxmm xmm9 + pushxmm xmm8 + pushxmm xmm7 + pushxmm xmm6 + + pushreg r15 + pushreg r14 + pushreg r13 + pushreg r12 + + pushreg rbp + pushreg rbx + pushreg rdi + pushreg rsi + + sub rsp, 10h ;allocate the singlefunction argument (must be multiple of 16) + .allocstack 10h +.endprolog + + lea rcx, [rsp+10h] ;load stack base that we are saving + call slp_save_state_asm ;pass stackpointer, return offset in eax + cmp rax, 1 + je EXIT1 + cmp rax, -1 + je EXIT2 + ;actual stack switch: + add rsp, rax + call slp_restore_state_asm + xor rax, rax ;return 0 + +EXIT: + + add rsp, 10h + popreg rsi + popreg rdi + popreg rbx + popreg rbp + + popreg r12 + popreg r13 + popreg r14 + popreg r15 + + popxmm xmm6 + popxmm xmm7 + popxmm xmm8 + popxmm xmm9 + popxmm xmm10 + popxmm xmm11 + popxmm xmm12 + popxmm xmm13 + popxmm xmm14 + popxmm xmm15 + + add rsp, 8 + ret + +EXIT1: + mov rax, 1 + jmp EXIT + +EXIT2: + sar rax, 1 + jmp EXIT + +slp_switch ENDP + +END \ No newline at end of file diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_x64_masm.obj b/.venv/Lib/site-packages/greenlet/platform/switch_x64_masm.obj new file mode 100644 index 0000000000000000000000000000000000000000..64e3e6b898ec765d4e37075f7b1635ad24c9efa2 GIT binary patch literal 1078 zcmZ{j&ubG=5XWb`DJB@*%~BA=L%=;Gk}d_~52VO$4J4q2U~MY6&1RFl{E&?scGnt@ zn(9GNy!ihFEO@PV4?T&H9`x2*oO!!jlNJZwd!P4xlX&_;U$Bg3z>p zje>}2kp+MsxE|w5hOUr>YC~(=fz6fwPdZd5+Hlb^P3{;ZO@Yuv96GG&+Gx?QfclNd zhy2KN&~>fNnlHQRR;U1cMyQ?hlQ$~k<0KBbB<0uD2#PTjVo+na7Q;#m=@=3m;xJOa zs2V#)&Db`cY;WzTF9)11;SjkVQWE!?bPTC%x3h3^F2;aBns5!i%m4&-*h69;~AUpZR%rDpm!zuXY+kc zFCz-n*^4&c)5~}y3e?r-Evy*n*(lp9r%ti58Y#l5&)rDjx5EbRd}nC+_8znRzz&#& XZ_Fi+`GM=5Rl{n4%KxAK>jC@)Nz=zi literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_x64_msvc.h b/.venv/Lib/site-packages/greenlet/platform/switch_x64_msvc.h new file mode 100644 index 000000000..601ea5605 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_x64_msvc.h @@ -0,0 +1,60 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 26-Sep-02 Christian Tismer + * again as a result of virtualized stack access, + * the compiler used less registers. Needed to + * explicit mention registers in order to get them saved. + * Thanks to Jeff Senn for pointing this out and help. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 01-Mar-02 Christian Tismer + * Initial final version after lots of iterations for i386. + */ + +/* Avoid alloca redefined warning on mingw64 */ +#ifndef alloca +#define alloca _alloca +#endif + +#define STACK_REFPLUS 1 +#define STACK_MAGIC 0 + +/* Use the generic support for an external assembly language slp_switch function. */ +#define EXTERNAL_ASM + +#ifdef SLP_EVAL +/* This always uses the external masm assembly file. */ +#endif + +/* + * further self-processing support + */ + +/* we have IsBadReadPtr available, so we can peek at objects */ +/* +#define STACKLESS_SPY + +#ifdef IMPLEMENT_STACKLESSMODULE +#include "Windows.h" +#define CANNOT_READ_MEM(p, bytes) IsBadReadPtr(p, bytes) + +static int IS_ON_STACK(void*p) +{ + int stackref; + intptr_t stackbase = ((intptr_t)&stackref) & 0xfffff000; + return (intptr_t)p >= stackbase && (intptr_t)p < stackbase + 0x00100000; +} + +#endif +*/ \ No newline at end of file diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_x86_msvc.h b/.venv/Lib/site-packages/greenlet/platform/switch_x86_msvc.h new file mode 100644 index 000000000..0f3a59f52 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_x86_msvc.h @@ -0,0 +1,326 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 26-Sep-02 Christian Tismer + * again as a result of virtualized stack access, + * the compiler used less registers. Needed to + * explicit mention registers in order to get them saved. + * Thanks to Jeff Senn for pointing this out and help. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 01-Mar-02 Christian Tismer + * Initial final version after lots of iterations for i386. + */ + +#define alloca _alloca + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 0 + +/* Some magic to quell warnings and keep slp_switch() from crashing when built + with VC90. Disable global optimizations, and the warning: frame pointer + register 'ebp' modified by inline assembly code. + + We used to just disable global optimizations ("g") but upstream stackless + Python, as well as stackman, turn off all optimizations. + +References: +https://github.com/stackless-dev/stackman/blob/dbc72fe5207a2055e658c819fdeab9731dee78b9/stackman/platforms/switch_x86_msvc.h +https://github.com/stackless-dev/stackless/blob/main-slp/Stackless/platf/switch_x86_msvc.h +*/ +#define WIN32_LEAN_AND_MEAN +#include + +#pragma optimize("", off) /* so that autos are stored on the stack */ +#pragma warning(disable:4731) +#pragma warning(disable:4733) /* disable warning about modifying FS[0] */ + +/** + * Most modern compilers and environments handle C++ exceptions without any + * special help from us. MSVC on 32-bit windows is an exception. There, C++ + * exceptions are dealt with using Windows' Structured Exception Handling + * (SEH). + * + * SEH is implemented as a singly linked list of nodes. The + * head of this list is stored in the Thread Information Block, which itself + * is pointed to from the FS register. It's the first field in the structure, + * or offset 0, so we can access it using assembly FS:[0], or the compiler + * intrinsics and field offset information from the headers (as we do below). + * Somewhat unusually, the tail of the list doesn't have prev == NULL, it has + * prev == 0xFFFFFFFF. + * + * SEH was designed for C, and traditionally uses the MSVC compiler + * intrinsincs __try{}/__except{}. It is also utilized for C++ exceptions by + * MSVC; there, every throw of a C++ exception raises a SEH error with the + * ExceptionCode 0xE06D7363; the SEH handler list is then traversed to + * deal with the exception. + * + * If the SEH list is corrupt, then when a C++ exception is thrown the program + * will abruptly exit with exit code 1. This does not use std::terminate(), so + * std::set_terminate() is useless to debug this. + * + * The SEH list is closely tied to the call stack; entering a function that + * uses __try{} or most C++ functions will push a new handler onto the front + * of the list. Returning from the function will remove the handler. Saving + * and restoring the head node of the SEH list (FS:[0]) per-greenlet is NOT + * ENOUGH to make SEH or exceptions work. + * + * Stack switching breaks SEH because the call stack no longer necessarily + * matches the SEH list. For example, given greenlet A that switches to + * greenlet B, at the moment of entering greenlet B, we will have any SEH + * handlers from greenlet A on the SEH list; greenlet B can then add its own + * handlers to the SEH list. When greenlet B switches back to greenlet A, + * greenlet B's handlers would still be on the SEH stack, but when switch() + * returns control to greenlet A, we have replaced the contents of the stack + * in memory, so all the address that greenlet B added to the SEH list are now + * invalid: part of the call stack has been unwound, but the SEH list was out + * of sync with the call stack. The net effect is that exception handling + * stops working. + * + * Thus, when switching greenlets, we need to be sure that the SEH list + * matches the effective call stack, "cutting out" any handlers that were + * pushed by the greenlet that switched out and which are no longer valid. + * + * The easiest way to do this is to capture the SEH list at the time the main + * greenlet for a thread is created, and, when initially starting a greenlet, + * start a new SEH list for it, which contains nothing but the handler + * established for the new greenlet itself, with the tail being the handlers + * for the main greenlet. If we then save and restore the SEH per-greenlet, + * they won't interfere with each others SEH lists. (No greenlet can unwind + * the call stack past the handlers established by the main greenlet). + * + * By observation, a new thread starts with three SEH handlers on the list. By + * the time we get around to creating the main greenlet, though, there can be + * many more, established by transient calls that lead to the creation of the + * main greenlet. Therefore, 3 is a magic constant telling us when to perform + * the initial slice. + * + * All of this can be debugged using a vectored exception handler, which + * operates independently of the SEH handler list, and is called first. + * Walking the SEH list at key points can also be helpful. + * + * References: + * https://en.wikipedia.org/wiki/Win32_Thread_Information_Block + * https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273 + * https://docs.microsoft.com/en-us/cpp/cpp/try-except-statement?view=msvc-160 + * https://docs.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-160 + * https://docs.microsoft.com/en-us/windows/win32/debug/structured-exception-handling + * https://docs.microsoft.com/en-us/windows/win32/debug/using-a-vectored-exception-handler + * https://bytepointer.com/resources/pietrek_crash_course_depths_of_win32_seh.htm + */ +#define GREENLET_NEEDS_EXCEPTION_STATE_SAVED + + +typedef struct _GExceptionRegistration { + struct _GExceptionRegistration* prev; + void* handler_f; +} GExceptionRegistration; + +static void +slp_set_exception_state(const void *const seh_state) +{ + // Because the stack from from which we do this is ALSO a handler, and + // that one we want to keep, we need to relink the current SEH handler + // frame to point to this one, cutting out the middle men, as it were. + // + // Entering a try block doesn't change the SEH frame, but entering a + // function containing a try block does. + GExceptionRegistration* current_seh_state = (GExceptionRegistration*)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); + current_seh_state->prev = (GExceptionRegistration*)seh_state; +} + + +static GExceptionRegistration* +x86_slp_get_third_oldest_handler() +{ + GExceptionRegistration* a = NULL; /* Closest to the top */ + GExceptionRegistration* b = NULL; /* second */ + GExceptionRegistration* c = NULL; + GExceptionRegistration* seh_state = (GExceptionRegistration*)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); + a = b = c = seh_state; + + while (seh_state && seh_state != (GExceptionRegistration*)0xFFFFFFFF) { + if ((void*)seh_state->prev < (void*)100) { + fprintf(stderr, "\tERROR: Broken SEH chain.\n"); + return NULL; + } + a = b; + b = c; + c = seh_state; + + seh_state = seh_state->prev; + } + return a ? a : (b ? b : c); +} + + +static void* +slp_get_exception_state() +{ + // XXX: There appear to be three SEH handlers on the stack already at the + // start of the thread. Is that a guarantee? Almost certainly not. Yet in + // all observed cases it has been three. This is consistent with + // faulthandler off or on, and optimizations off or on. It may not be + // consistent with other operating system versions, though: we only have + // CI on one or two versions (don't ask what there are). + // In theory we could capture the number of handlers on the chain when + // PyInit__greenlet is called: there are probably only the default + // handlers at that point (unless we're embedded and people have used + // __try/__except or a C++ handler)? + return x86_slp_get_third_oldest_handler(); +} + +static int +slp_switch(void) +{ + /* MASM syntax is typically reversed from other assemblers. + It is usually + */ + int *stackref, stsizediff; + /* store the structured exception state for this stack */ + DWORD seh_state = __readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); + __asm mov stackref, esp; + /* modify EBX, ESI and EDI in order to get them preserved */ + __asm mov ebx, ebx; + __asm xchg esi, edi; + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm { + mov eax, stsizediff + add esp, eax + add ebp, eax + } + SLP_RESTORE_STATE(); + } + __writefsdword(FIELD_OFFSET(NT_TIB, ExceptionList), seh_state); + return 0; +} + +/* re-enable ebp warning and global optimizations. */ +#pragma optimize("", on) +#pragma warning(default:4731) +#pragma warning(default:4733) /* disable warning about modifying FS[0] */ + + +#endif + +/* + * further self-processing support + */ + +/* we have IsBadReadPtr available, so we can peek at objects */ +#define STACKLESS_SPY + +#ifdef GREENLET_DEBUG + +#define CANNOT_READ_MEM(p, bytes) IsBadReadPtr(p, bytes) + +static int IS_ON_STACK(void*p) +{ + int stackref; + int stackbase = ((int)&stackref) & 0xfffff000; + return (int)p >= stackbase && (int)p < stackbase + 0x00100000; +} + +static void +x86_slp_show_seh_chain() +{ + GExceptionRegistration* seh_state = (GExceptionRegistration*)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); + fprintf(stderr, "====== SEH Chain ======\n"); + while (seh_state && seh_state != (GExceptionRegistration*)0xFFFFFFFF) { + fprintf(stderr, "\tSEH_chain addr: %p handler: %p prev: %p\n", + seh_state, + seh_state->handler_f, seh_state->prev); + if ((void*)seh_state->prev < (void*)100) { + fprintf(stderr, "\tERROR: Broken chain.\n"); + break; + } + seh_state = seh_state->prev; + } + fprintf(stderr, "====== End SEH Chain ======\n"); + fflush(NULL); + return; +} + +//addVectoredExceptionHandler constants: +//CALL_FIRST means call this exception handler first; +//CALL_LAST means call this exception handler last +#define CALL_FIRST 1 +#define CALL_LAST 0 + +LONG WINAPI +GreenletVectorHandler(PEXCEPTION_POINTERS ExceptionInfo) +{ + // We get one of these for every C++ exception, with code + // E06D7363 + // This is a special value that means "C++ exception from MSVC" + // https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273 + // + // Install in the module init function with: + // AddVectoredExceptionHandler(CALL_FIRST, GreenletVectorHandler); + PEXCEPTION_RECORD ExceptionRecord = ExceptionInfo->ExceptionRecord; + + fprintf(stderr, + "GOT VECTORED EXCEPTION:\n" + "\tExceptionCode : %p\n" + "\tExceptionFlags : %p\n" + "\tExceptionAddr : %p\n" + "\tNumberparams : %ld\n", + ExceptionRecord->ExceptionCode, + ExceptionRecord->ExceptionFlags, + ExceptionRecord->ExceptionAddress, + ExceptionRecord->NumberParameters + ); + if (ExceptionRecord->ExceptionFlags & 1) { + fprintf(stderr, "\t\tEH_NONCONTINUABLE\n" ); + } + if (ExceptionRecord->ExceptionFlags & 2) { + fprintf(stderr, "\t\tEH_UNWINDING\n" ); + } + if (ExceptionRecord->ExceptionFlags & 4) { + fprintf(stderr, "\t\tEH_EXIT_UNWIND\n" ); + } + if (ExceptionRecord->ExceptionFlags & 8) { + fprintf(stderr, "\t\tEH_STACK_INVALID\n" ); + } + if (ExceptionRecord->ExceptionFlags & 0x10) { + fprintf(stderr, "\t\tEH_NESTED_CALL\n" ); + } + if (ExceptionRecord->ExceptionFlags & 0x20) { + fprintf(stderr, "\t\tEH_TARGET_UNWIND\n" ); + } + if (ExceptionRecord->ExceptionFlags & 0x40) { + fprintf(stderr, "\t\tEH_COLLIDED_UNWIND\n" ); + } + fprintf(stderr, "\n"); + fflush(NULL); + for(DWORD i = 0; i < ExceptionRecord->NumberParameters; i++) { + fprintf(stderr, "\t\t\tParam %ld: %lX\n", i, ExceptionRecord->ExceptionInformation[i]); + } + + if (ExceptionRecord->NumberParameters == 3) { + fprintf(stderr, "\tAbout to traverse SEH chain\n"); + // C++ Exception records have 3 params. + x86_slp_show_seh_chain(); + } + + return EXCEPTION_CONTINUE_SEARCH; +} + + + + +#endif diff --git a/.venv/Lib/site-packages/greenlet/platform/switch_x86_unix.h b/.venv/Lib/site-packages/greenlet/platform/switch_x86_unix.h new file mode 100644 index 000000000..3a9518655 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/platform/switch_x86_unix.h @@ -0,0 +1,105 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 3-May-13 Ralf Schmitt + * Add support for strange GCC caller-save decisions + * (ported from switch_aarch64_gcc.h) + * 19-Aug-11 Alexey Borzenkov + * Correctly save ebp, ebx and cw + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'ebx' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for spark + * 31-Avr-02 Armin Rigo + * Added ebx, esi and edi register-saves. + * 01-Mar-02 Samual M. Rushing + * Ported from i386. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +/* #define STACK_MAGIC 3 */ +/* the above works fine with gcc 2.96, but 2.95.3 wants this */ +#define STACK_MAGIC 0 + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) +# define ATTR_NOCLONE __attribute__((noclone)) +#else +# define ATTR_NOCLONE +#endif + +static int +slp_switch(void) +{ + int err; +#ifdef _WIN32 + void *seh; +#endif + void *ebp, *ebx; + unsigned short cw; + register int *stackref, stsizediff; + __asm__ volatile ("" : : : "esi", "edi"); + __asm__ volatile ("fstcw %0" : "=m" (cw)); + __asm__ volatile ("movl %%ebp, %0" : "=m" (ebp)); + __asm__ volatile ("movl %%ebx, %0" : "=m" (ebx)); +#ifdef _WIN32 + __asm__ volatile ( + "movl %%fs:0x0, %%eax\n" + "movl %%eax, %0\n" + : "=m" (seh) + : + : "eax"); +#endif + __asm__ ("movl %%esp, %0" : "=g" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "addl %0, %%esp\n" + "addl %0, %%ebp\n" + : + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + __asm__ volatile ("xorl %%eax, %%eax" : "=a" (err)); + } +#ifdef _WIN32 + __asm__ volatile ( + "movl %0, %%eax\n" + "movl %%eax, %%fs:0x0\n" + : + : "m" (seh) + : "eax"); +#endif + __asm__ volatile ("movl %0, %%ebx" : : "m" (ebx)); + __asm__ volatile ("movl %0, %%ebp" : : "m" (ebp)); + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("" : : : "esi", "edi"); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/.venv/Lib/site-packages/greenlet/slp_platformselect.h b/.venv/Lib/site-packages/greenlet/slp_platformselect.h new file mode 100644 index 000000000..b6a3e704a --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/slp_platformselect.h @@ -0,0 +1,65 @@ +/* + * Platform Selection for Stackless Python + */ +#ifdef __cplusplus +extern "C" { +#endif +#if defined(MS_WIN32) && !defined(MS_WIN64) && defined(_M_IX86) && defined(_MSC_VER) +#include "platform/switch_x86_msvc.h" /* MS Visual Studio on X86 */ +#elif defined(MS_WIN64) && defined(_M_X64) && defined(_MSC_VER) || defined(__MINGW64__) +#include "platform/switch_x64_msvc.h" /* MS Visual Studio on X64 */ +#elif defined(MS_WIN64) && defined(_M_ARM64) +#include "platform/switch_arm64_msvc.h" /* MS Visual Studio on ARM64 */ +#elif defined(__GNUC__) && defined(__amd64__) && defined(__ILP32__) +#include "platform/switch_x32_unix.h" /* gcc on amd64 with x32 ABI */ +#elif defined(__GNUC__) && defined(__amd64__) +#include "platform/switch_amd64_unix.h" /* gcc on amd64 */ +#elif defined(__GNUC__) && defined(__i386__) +#include "platform/switch_x86_unix.h" /* gcc on X86 */ +#elif defined(__GNUC__) && defined(__powerpc64__) && (defined(__linux__) || defined(__FreeBSD__)) +#include "platform/switch_ppc64_linux.h" /* gcc on PowerPC 64-bit */ +#elif defined(__GNUC__) && defined(__PPC__) && (defined(__linux__) || defined(__FreeBSD__)) +#include "platform/switch_ppc_linux.h" /* gcc on PowerPC */ +#elif defined(__GNUC__) && defined(__ppc__) && defined(__APPLE__) +#include "platform/switch_ppc_macosx.h" /* Apple MacOS X on PowerPC */ +#elif defined(__GNUC__) && defined(__powerpc64__) && defined(_AIX) +#include "platform/switch_ppc64_aix.h" /* gcc on AIX/PowerPC 64-bit */ +#elif defined(__GNUC__) && defined(_ARCH_PPC) && defined(_AIX) +#include "platform/switch_ppc_aix.h" /* gcc on AIX/PowerPC */ +#elif defined(__GNUC__) && defined(sparc) +#include "platform/switch_sparc_sun_gcc.h" /* SunOS sparc with gcc */ +#elif defined(__SUNPRO_C) && defined(sparc) && defined(sun) +#include "platform/switch_sparc_sun_gcc.h" /* SunStudio on amd64 */ +#elif defined(__SUNPRO_C) && defined(__amd64__) && defined(sun) +#include "platform/switch_amd64_unix.h" /* SunStudio on amd64 */ +#elif defined(__SUNPRO_C) && defined(__i386__) && defined(sun) +#include "platform/switch_x86_unix.h" /* SunStudio on x86 */ +#elif defined(__GNUC__) && defined(__s390__) && defined(__linux__) +#include "platform/switch_s390_unix.h" /* Linux/S390 */ +#elif defined(__GNUC__) && defined(__s390x__) && defined(__linux__) +#include "platform/switch_s390_unix.h" /* Linux/S390 zSeries (64-bit) */ +#elif defined(__GNUC__) && defined(__arm__) +#ifdef __APPLE__ +#include +#endif +#if TARGET_OS_IPHONE +#include "platform/switch_arm32_ios.h" /* iPhone OS on arm32 */ +#else +#include "platform/switch_arm32_gcc.h" /* gcc using arm32 */ +#endif +#elif defined(__GNUC__) && defined(__mips__) && defined(__linux__) +#include "platform/switch_mips_unix.h" /* Linux/MIPS */ +#elif defined(__GNUC__) && defined(__aarch64__) +#include "platform/switch_aarch64_gcc.h" /* Aarch64 ABI */ +#elif defined(__GNUC__) && defined(__mc68000__) +#include "platform/switch_m68k_gcc.h" /* gcc on m68k */ +#elif defined(__GNUC__) && defined(__csky__) +#include "platform/switch_csky_gcc.h" /* gcc on csky */ +#elif defined(__GNUC__) && defined(__riscv) +#include "platform/switch_riscv_unix.h" /* gcc on RISC-V */ +#elif defined(__GNUC__) && defined(__alpha__) +#include "platform/switch_alpha_unix.h" /* gcc on DEC Alpha */ +#endif +#ifdef __cplusplus +}; +#endif diff --git a/.venv/Lib/site-packages/greenlet/tests/__init__.py b/.venv/Lib/site-packages/greenlet/tests/__init__.py new file mode 100644 index 000000000..7ff5afb97 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/tests/__init__.py @@ -0,0 +1,135 @@ +# -*- coding: utf-8 -*- +""" +Tests for greenlet. + +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import unittest + +from gc import collect +from gc import get_objects +from threading import active_count as active_thread_count +from time import sleep +from time import time + +from greenlet import greenlet as RawGreenlet +from greenlet import getcurrent + +from greenlet._greenlet import get_pending_cleanup_count +from greenlet._greenlet import get_total_main_greenlets + +from . import leakcheck + + +class TestCaseMetaClass(type): + # wrap each test method with + # a) leak checks + def __new__(cls, classname, bases, classDict): + # pylint and pep8 fight over what this should be called (mcs or cls). + # pylint gets it right, but we can't scope disable pep8, so we go with + # its convention. + # pylint: disable=bad-mcs-classmethod-argument + check_totalrefcount = True + + # Python 3: must copy, we mutate the classDict. Interestingly enough, + # it doesn't actually error out, but under 3.6 we wind up wrapping + # and re-wrapping the same items over and over and over. + for key, value in list(classDict.items()): + if key.startswith('test') and callable(value): + classDict.pop(key) + if check_totalrefcount: + value = leakcheck.wrap_refcount(value) + classDict[key] = value + return type.__new__(cls, classname, bases, classDict) + + +class TestCase(TestCaseMetaClass( + "NewBase", + (unittest.TestCase,), + {})): + + cleanup_attempt_sleep_duration = 0.001 + cleanup_max_sleep_seconds = 1 + + def wait_for_pending_cleanups(self, + initial_active_threads=None, + initial_main_greenlets=None): + initial_active_threads = initial_active_threads or self.threads_before_test + initial_main_greenlets = initial_main_greenlets or self.main_greenlets_before_test + sleep_time = self.cleanup_attempt_sleep_duration + # NOTE: This is racy! A Python-level thread object may be dead + # and gone, but the C thread may not yet have fired its + # destructors and added to the queue. There's no particular + # way to know that's about to happen. We try to watch the + # Python threads to make sure they, at least, have gone away. + # Counting the main greenlets, which we can easily do deterministically, + # also helps. + + # Always sleep at least once to let other threads run + sleep(sleep_time) + quit_after = time() + self.cleanup_max_sleep_seconds + # TODO: We could add an API that calls us back when a particular main greenlet is deleted? + # It would have to drop the GIL + while ( + get_pending_cleanup_count() + or active_thread_count() > initial_active_threads + or (not self.expect_greenlet_leak + and get_total_main_greenlets() > initial_main_greenlets)): + sleep(sleep_time) + if time() > quit_after: + print("Time limit exceeded.") + print("Threads: Waiting for only", initial_active_threads, + "-->", active_thread_count()) + print("MGlets : Waiting for only", initial_main_greenlets, + "-->", get_total_main_greenlets()) + break + collect() + + def count_objects(self, kind=list, exact_kind=True): + # pylint:disable=unidiomatic-typecheck + # Collect the garbage. + for _ in range(3): + collect() + if exact_kind: + return sum( + 1 + for x in get_objects() + if type(x) is kind + ) + # instances + return sum( + 1 + for x in get_objects() + if isinstance(x, kind) + ) + + greenlets_before_test = 0 + threads_before_test = 0 + main_greenlets_before_test = 0 + expect_greenlet_leak = False + + def count_greenlets(self): + """ + Find all the greenlets and subclasses tracked by the GC. + """ + return self.count_objects(RawGreenlet, False) + + def setUp(self): + # Ensure the main greenlet exists, otherwise the first test + # gets a false positive leak + super(TestCase, self).setUp() + getcurrent() + self.threads_before_test = active_thread_count() + self.main_greenlets_before_test = get_total_main_greenlets() + self.wait_for_pending_cleanups(self.threads_before_test, self.main_greenlets_before_test) + self.greenlets_before_test = self.count_greenlets() + + def tearDown(self): + if getattr(self, 'skipTearDown', False): + return + + self.wait_for_pending_cleanups(self.threads_before_test, self.main_greenlets_before_test) + super(TestCase, self).tearDown() diff --git a/.venv/Lib/site-packages/greenlet/tests/__pycache__/__init__.cpython-311.pyc b/.venv/Lib/site-packages/greenlet/tests/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c06d74d80ca67d8e1d7fcc6ff91a8768c1256bde GIT binary patch literal 6412 zcmbstZExGg`6!VxB}-L%dS2Qn8A+jy&ZVgzh2d*@GRTEaA*uZ)lEQN5JvTxR z;9o1LF4`A?z77|XyQHYhU5Z(~6HEp<>7BJyOybU>Wao6J@0_e^YGNXf6O&k$bBe4D z`F!6JMoGpDisNctDQdEi$rkchgC<_eT+XPOd=Buo0?y<#VWOBzYtS+ZO)crXqR44N z**Ym}LVo-b)KsYYMIgE?3+a3@N4hyxk>vs)td_~j@aC-v0Pcga=_1B5C5;nK1vw{W za+5+@k;PoGVDpKQPA#vAijWmEIl48fR^j zmN+LRgGwy!&{}N*bcw8xmS(OnJ5R}7;toRZt(4YQCxh1lzk;t|B~)Tcu9Ev6%;bSR z8?wox=RgBso0DFXRWhn(av4p|s-{oXM69V-GTKFxPm78ojw`b1F60Y11bofF6)YA6 zEKg8{0v^{2ve_aCIr)kpBwI{(T2W1Jng}f?W@VEb2RT|TCo*Zxj8LVh>5k3EJtbc= zxyzzblvT2;iCXzyI=+AG9aYBa*iXgr%(ys~2ZcPFFXFU3b`m}^HTbSPK6tcH7(7?h z@;DdV>)-Rd6z+(1>!173`c3oK{`leVJ}hq0Mm{ZlT$(?=5dY%Uha=_SAtQK5 z=MO!F8KTi7Yw|E}*n2@ReS(n9OGSm?enEJ@C@Qrcy5#!^_rnmpnSihb)&rvU0k~oR zs-6&cxQbST+ITY5VdR$mJpCo~eB>~5V&o~-i@ZqkOYBW1#mOFtn{Y`Uz+0r26c2wd z{CyIiYL&d;7W^}4f{}bT`BZ>nt$?-7psP$O2$~!)c}sAU|GxiZ@s07fj^H4CcQj3$ zgjI-AQKv!7{4SV9!Baw)tX^~-%!IbsF5$Wh`mKea>u!g!yPHi|vqBwkbUGT~!dai0 z1_Yc{z^XUXs@pX(^LlCG!%VTHLyZGR+t}5wGzhv@X&T|GjllQ*@42&e4zFub>l+Bd z@2b@|_PR?&VCmSstnhQPsG#Ih)<`xEbq84ZFejsN+a za&6i@ICywE{>CZD1JuOo{-ocGXtlw@xC~i?ED$GVu5*T7N8d&(Vv8C$_JStRz%NKe zERw7N6NSYjbu;4@Wmdder&8r~J}0S|XsQ{hrx3Ln)G`3GL%v#o6vK}D0txq+1SFHA z`3d#_p5#ncm6ZvzlQ>)O&VqxNy3+1k34|e%rU)cQF@5hB!BLA78iWC2N;EW3r)9>k zz)lLVAKQ9>@50;|`fq+Nt+sdKsMreE0?e}&*jtrC| zTaCz8ef!bH$Wc9Vv=ZB3#CBHQsN)#(I5u34?J{D!^gU-5V`uc(nI(Vw+_tj6+wgbm z{%&yevzKpOp7$*Vd-Y)NQYfl-zElnk8lgcwG)SvE^_NdqI@kZbd$`=a%jn+q#Lcwt zeg^SlHwhxUACn4IN*)W76bfN1y)3_g{CI>s~DxxnV z5;~9WG7P#ElbEyUzN;4Gk_;vR`@Y+B4Go*jRg;~{faQ`;ClWWPm3;3#I4S4AUh(1S zq-_;6f3pq>LkE>SBzx-NA)8bL4(b5_-+hC=Ar^wzt~LsmJEBXGu6gG6-aC8erMV+> zN2(lZ4=+c02@bUui;^mWV+V-D=njw!wqXZ4n|EN=bq|8?13LhJ8MfEoMb?iG0RwVm zfm2Zqa@Jg0#$;C=E62y6<$qZ7Bw=t0z{;8?)2$Y>m}DbK7Vm}^J_^9}$ydQM3Pg4$BdA1C67MAv zH7^%%$ZERt#WMT_j8Q)a@ZAmc+=IehbMN1d-HCyXdpjwZIlAPJ%$~k=dIo-#)+otS z+m<5GX~}B^dmP{V+wR|YS2^fY~}IK{FDlttbmbVb}C)J{l+h zoP=FXz)>clU6k$fwwe&3RV|Lwvx=-HGz=#NSxSswqjaZ^53Mjry6|b3g4z1Ec;!_6 zzz&v266dvt!! zYU8nYW*ENtS(6iO+>a7+8qbRlv`+U3nHbT^dRf)?1Np6ByWzF7u@Vw&?jTV+f3?0x z-i?_u;5NN;EpS{$3k|bb;ozJze34#Ek$#$&F{8;=xc(>>WQ?~%BjB?3P67J?$2$oa zB!Hwac!&U!9^lsjm{D79jVTtmV4?t~SAg3QIPVIAN_4XBb@7{kPq*0$KtFaB+SC$& znvHtfKDjv0micaj?|#JhE%JS3zTe>cb-sUz56}8<`Dgq~eXo@J_8EQqW>|wyENweh z-gd&+c7oKlRCxa*eqfOwSkR0uN51Ybj=opsMS~Z0Uaa&dAN7wc_K%eN4;cLi2z{?k zpVf**1V~NpZ-6u_R*Bx(Id8JCi)<+ff++v00>ZP66L7+rmS#aV9-1^;SVR$=lnWk< zL*v^i?t1d=9yR^yRHkrF7V(MvmE1|Vl4yaeDoBEHO`ufBRKBCYt)>aQRwu_lgEog0 z&qKqseIYeu5&oLcr2v2+ms-PfyXQB45iPgwFk0bU&v+vhe|YBP@(+k-i4Qc&o(Qqb zZ#DR>y7kn8hih~+8NvhbCA@`ztpw~KV3+`^qvZ5O{S$tRU@I%!MXE%DsWM`+7Bf)S z*0iiBaAU*Zx1p6fv7gXrLwAG%ViW4u0AP*Q5AHt(w(D$fCDEg^-HF|0C6s6*m563_Hl`xtZK(4L@(B8 z7FWB3Arr+(0{RKq4B&hIVC^2~Fn$lJ#Ol;pfK@lcFjdyguvJ6=kC-hw8fbhfXp`=I zDyUy~KFcV0gZ`FLr|x_zXr1nSDriJ^J{9K>;7~zP-T5q|mvrZ|dSc6HpYD7rXs_;k zmQk1Pe5#%Z1D8{)!94qfv_4zudg(mFfY!Vi>cIp&6~4XVZ8yB@bbdpH_dRKGhy2eF OfG2d=vo!`&QT+#a$zuJn1q`%69W)>Q*aAag3KN40Fi@mh|0#6}7(v_g zoIB)@L&;tj=tnPyXYSm`x#!+{?m6e4d;iMmv{Mj%fA?+fFS{w~U+|+4O!>&uKQmC& zZHl8fI!0ZkM`;@4hL~a0K;FhtBY88U47`mo(^d1RIbX&yY9V>nQ7dn_Vk@9tBCQs_ z3U7}2gr=xZ;je~K$4k^P>FXqE-Z9F)L_M><-l&sjp{{eZ;w9=@%Idm!SF-LU>RHR` zxnH7=t*lPvOVqKK)$wqS_o-1Y#{#S}P{%0F`98%}@YSCfVZ7m=A8((5;%j&#=lTR@ z{8RX=LGY70Zm3hq*Ot|(gF1DeK*3K7#VOtzVhSI8)o6X($a$dUdV<9ZSgO`x*+lZH zA}#Q( z-jTtR!C}Qba;E3p;ILxtId$q>|M`<=6wk3U{r$nA{*lldJ;C!sgTb@kRcf`g;S+q|s5mImT+SaHaoRsn!zMW?9{#MF?c zpp%C1@1cU-4`Fa3o)CC{>N4-2h+gC4{>0c7K9cftQ_%ehe~b@LMlSP_NwM2b%J+uj z{xRMkP9|efp7W;?{;>ZlpSqmjI{neO|N7-< zDe*)KafwrElYk4G^Xu9h9M`uMiG@Y6lhDh@Q&AwDq^M0GvdL&N352bu-#>CWDw4*d zB9NNms;=}!uYu^4|<1j?ba zVHIhL7gPRJ^eUg2N{NU3shi1YBpi#~^hZ+~anElC#(?w#nodBE{bMkKgjTh8*tVGD zBhm4j{%c_&8jhz(!7=`F_*yhECHS}HY4Il$iI`uEPV-`WH^DFhoa>H~X%1=A`72ss zkhMi*9RD|b@4*XaMP3ju91o90$HEs9Nj^Rdcq9CU0T}Vgt~dFyuAXGFYh)^wfc9e- zx`A1)T^NdvT@a%wzAG7yOok_T@xp|_^YIv;+JOTi?$BE7PTo{1RWigP9YQ6vKLmdf zBeT?6E!EgG+b1)1IfrZZ#8XJ5bj*$Go-p?Xh?FyTN|PuQB{UkSR6)Z)*(+F!1kRwB zUTI4IJwuU2Vw`@3jNcn!VN&G>TqFf~;0Gp}j3=(gaS322^MgHIGmIRFYe&r<4@YBD z0?Y=ZxG-MQd8LMkg7wQ;u};OKDI7qBL53D8fN*uH1UEzlT-gM?g&Dg6z|dK#20sp6 z?W$$-8bzCq=3M)Kcw=rxYTTD~?U!Bq?=xA~5!rPl!;rxhJWwwJe=QWG$Wv_ZHpNq; zG)I9Frcq`n6+_U?UK9rXf{+k`?MB5K3dO@$`A|r)heB5q+*AzXY$){3R5+&Q{E8y& zsC3r>UI76If6)bCR{P}`>ujG|7E37h2|lF?BXMIQ>!DOBks!m3oB<%i8G&F%v4q}8 zL?(~*>KF*w0RK-rNcB{q&+v6ci*vM|C9wZN0l5pt!6@Doh0PGhMI`dE@sgQQ96)s_ zPxiDoPe6A`Vhk#ZIP$a9s@J!0bg3!p4anYr#0Jy}DdAy?fpUb{PKey5N{KDy^)#*5 zr^7&65Gb`kyWvzyPz)21c7qTABnpGmB4Q(cKbaK85entYg+fJ=OA_NySR=Xq&MS*4 zJ;}j#lYo;UY(mh0pcTP(1dRx=zbXg#F@|6g{^BbDiX51icl9<*eZl zQ$iFJ_P5_|U#~E+S=2nJ5qK2tnnd)EN8_C62PKhLx}ev1RKcK4 zMZQy~T@VX49G`$fs**+Rgc>v@fanGFHFlF|#fh*m27=fhNyK8H$Pi8RkR20N1Fn7lvB%r%c_Fcr{1TahGs_Qe% zoIL|Swf7qmi2?zc?h3rskfuY0v7yo+LRE4Ngh0iou|X)Wn{}N)(OBLIG$&rR6KdI6 z#G)$JTwBN8D;Y+%w&Yyi{4{Q`ZgD{hdl8ha+Z~vOU!YNU4stmz}2uCQ6IL~upNaRyz zlkG+##DxRUqHqv^h?L;cCT0Q7-gI4g=QW=G0an-t0C>9A4?OKGynMCr<;c}Hz{{0u z+=7f!j|N2(#%d+V7GlGfK;MFATZD4Q3b7F*1ToIlk+ z49Y)%sYcL)3Nr~hP4V(K!ca}!{Xv^x42lYUL&T*4%vxaA9{8MYUeB)Og#QJU6CE)9 zpoQ!d>zWT_4rLDIytVUtS6$xu-di{4Zf2M@mSWvM*|W&VwcT0o4%xe7#j!(j>{v5c zoG0nWZ5?vk;YV$~D{Z|Gdb4fE<+kIJy9J(StKOzHih(jZXr;DpCpG$3+WH<0XWItl zw!w#|SK5MVHGpe2to7{KGich~^6PHN^(sC`P65o-G|W$}nJJHNq47~=>q=#7wsNan zxfSH1t&xCCPtN6;4`*&e=?b~|x8b9Ad1Jv0=IND@&_CZ8%JQmjyhwDLGPY~Bc+h?@i5kqWXu=!1~ z=+$USI1ES?^LR9t;svm^tuXr&;2ycGm?wn9_0(ljK)@*$S^$*V$d-^=WV&|!+^ac% zi#1TYgOTj2nfu<-$UW}23D99MBWp(5ee^2|z}E=SUOc*9G~vP_oxcwe6ip%#OB2+L zPW0e@Ax-yD`UR;MLNi7zak2RV;G1D)Of%-RVM!B4fL;rnF>OpUX;a!f&P;;{(Bq-0 zxfYIjj_@kmlg?Pu78r0-aJu2}*?1V-4YNX7o)|T2;#uy)m2{&}_6mYYo&>@|=`Nnp5f{*hzlETsH zo$F^(;FAd<1p;Jzy!&u00kn%pyR{l$079`Fz`wz7mXf^t;rV&TQec^0-u08-MdpLS zg+Vp76q1RaW?Q>D#MT3xzjgZo?i<<;L>jM#ZzyJPOMzQQVXh>i@ph}KD^DZoz_f8* z1P@-61J)$HF-6coP)tMvD-6;pBG;gN!k})B*icD7rW;?_&A-P!y$1mFtE(Cr^Oc-; zm*m~`*zL)fR^48;C-=Wl-rwXQ!omb3PF^Q(`$Qy^Z%f4C zE3R8x2=?tEw7941H(0d!yx&0`aSO35R;z0kE_`rl;ZnxFYPHYVZ?SW1hJEaC$qv}o z7;HOotb6W_N9>jrc1xCRlG!GSZOXNGXZq&eklD61gVolMW9#s9G4OGh#2#1%pUwgG zx!0yeAFF7ZSJ>t(8<1Ia{NzywR@gw6Z3Ao)+m>tZ%A?M0Y031-Y(vgf2jaomu}%Cq8fZTdW&7_C zL8ojA-i1)KHNavGY@EZ<=<-v;#tL%X$}wz==>=^V{Yq7pTLxo))sn1COl` zONIrJpJpKzi;i`ZFJRkdsG(R?=cuSSBEZ-}C=!NK4&e-Bt+S4tdFvej zRh7S*zX~Ws^o7q-j~&%_ydQ6p907P%S=Zc&MZ3(lJYsjOusgEsE}7jWvAc4Px;w)k zza=@g!K0R{klC$|*xf7a?ku}kX7@_$Ueqe-@279QJNK?+ZG3@wbrePj?Tjlxf*Npl zry5(OF3O_z5E@dNLoj*LsOOi-Nl7j%BFY2cvD3o+RyiB=ODQ;tHPVb5sb?0T$v30d9M-48mt|d<4&ZNdu?NLixorq`KTt(XW z5q+oZK>a@cR_hOqq*|*9dR10(h~b}!c7}aF?4&nk%*3!Z*lHhpYv%WS>2S^+M3ebVde!5f@BT;6@9H1c zOHF69o^!J2oW!16^HHp4zInc7zGd#v;;zN;V%v(tFFE|b9A5VQ{H?oh-5Zcv55lAF ztR0nF+4e>FtvFgFM+?dO(ovDQcIyyeXQ|-%=D42KG=u9hkG9Gk(y3rJ*Q>QX^B1kA7*fm zWUkGR%}3@VbAOz5Yy#_L@tu5^dza12!m_w5e&)yq_Q-)f_vw|u0V#0c{<#OQJpi}J z-@WzdNO0vy@ZmezBd6sfr=_#!R*syLj+}d3<;(PE`X5(SXZlyQfoNTEY>^yW2tBz# z$I`&kKrXQDQDE;%VDG*0Y~Y9-I3fj(teFhWfAke)@P3E>nm{n8oZq2gO5s2urRtVa zJ&Q64zn@+LuGa5V%FpFsTV4&)sibyM&*-%@>}`FetGCqN=0Jk#eI4M9V+59Cpp>?Q zDeg<2i^s&7^?1M?tVvFgwlA?OnK7ZSbK~7ey6h^Fkc5)j-U3EU3*bvM=#K<(f3#Gh zue73N*366v`pgz`m+%B+T}a{CKt7-kK5crj14S?O2_+?(x_}9EXj%X6C1Dn7Q(KB9 zIBV&=eMED%J4QYB_u#}D_fsi6kI4t{`@$(;ni1*usPkmMrR`hnK_Vf^S^B_;um@_W zX9YyX79QA#c-FIl-=qTw6OoR*-(+jAw6*tM-!ij&`ZEhe%O2HVV(Y&Fmq$>!OxG6f zE8tZeyqm&BIXp(}Zg(ptAsn9oZywTW$txjY8+?)dnYw+e0)G#n0vlDm=0Oe&iCb8; zW@oWD9vBOFcBrZYyrdv}4*?EVyIJ+iOkx6_h6`^3P%83>^Y+B5WUEZcZmZaiH$8}ayVH+$@cTE=lf7xTg!DqY2=%|FDq?2AdD}xGKn@ zKb&^@a_(v@3yB&qLK)l+dSMOjE&A5_hSZv_u()86u_+Z1MN{=GyBFGV>1D@8t}E?(W3@lrwu0X5Np6{ z$7~JMyG*ci)=x{l;W844 zm*N#k(Nek}5)8LMnw4H-x>e>>&QRktXMEqP*LEnHU|-4v1r*=|>qtV8`cwh%6I!oe z(;JW^RBfzaL21HLD<12C@sH~@AB5IYC(eVlD9Yi~_7rVjcC4$ih zy;ZDu5r{x{RxMy`OEvAw zd$X2ZvSk;LXY&0`h`eA2ka2!#vS;@F$;J0Ct{F_G!yso%!B@8$fP^@=0sFJ!F zuc?hsrQkkZC?ud-R}2Y}cxdvjOL8y|Hz-9yzJSv!oWgPzxa}Af5^=={H-415GiQTA zyrg?F7%ICBTv?KpzZmQ-N$M%w5q6d&_6{mlC7;@*Vc|#Eel>z0Ai%2}gi+xLSA^@D zcrlqA;S$BFST2V}a^1_UUP%)CSiTDZxxPW$l z-%g40=G;w^`&Fs+)mdk*rfy;S_PZaxE43ZW)*O;+4oOs1&eJA&MwXjD>-bIgUw2Cf zhO-?ba>vN53obf*-0`#SpLR>_C$jZJa{Z7*)ohr!#yDyB8l{2F7W~wJho)`7let0AJLRpP-}*uO zLi_CT_fO;+J0+$bo;AjbN=gG&CcsLq2g~NKF!k$VRz=JJ_mkGB=fCE!eWm7ptuJ)J O#M0h1YCRx}?0*0fS0Moa literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_contextvars.cpython-311.pyc b/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_contextvars.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6b3b2f0a5989978a1c478532a308c69bd4d1c7c6 GIT binary patch literal 18510 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 Jfh60L9|1A7Et>!U literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_extension_interface.cpython-311.pyc b/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_extension_interface.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9cd34d27f997d50ce11ee3b904f91fc0490c1478 GIT binary patch literal 8587 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 L_+Nk$OqTx#ss_hE literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_gc.cpython-311.pyc b/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_gc.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fc326888ca12ff928dca2a4a0ef46b252aeff760 GIT binary patch literal 5516 zcmcgw|8Eq>6`$R`FKe@h?~HBEq_)qoO3gFCbmr;HL0aWONeuKr#HyqG3XNzZb!yHu%9r7*bm2A$CbGmX-y`ZZXRfo}`{8nM(`;fU!bb``> zWZZQ!A!t0%kR|{P>k%zjfyYt`di@%5?p4hk6LxW<{VQEr-vxVaz?M|iTp1?zsk zUjwz|qStsc;c^k!vITynsame)>PHAlat~Iz>aCU|3uJ{EQ*{I<_wUAGoW3MVSjv7vO#j$Q#vqWXDTKq5|4UC-xq({7&D zO?8e^J#X3(<4V?4FWCIFYDd*VE~l%eEf`k~J3LFX&|w>N26nYD2L(wn44s53++S*p(E6e@%C^W9r^Kh(Ir1qHniWRa{%JC=X+xo9QR zf7)&Bd8?cpv63T?l4B2(W98(yl^iciCoSn@ky{g+mz$TQWvM7twn@d|rGv`{i*Hw? zj^exctVxMd>#HlH_fP%q)PrLWj{SM`tI=}*VXOaeSvq1#M@rI>iYPr2J0FUjcY5#i z{#x{Ch}W;DdMp-1%@e0BQO9gE%hj~ese>SJ&oR%*M-31fVBoI4MHwx{7`cC)^ zG~Gq-sYvnS4;{`|p&{Kw(dp0*B)BmYy$!`BQDme$khCFb2a*% zPL>*Q)wSaijNbrRB0)K!wY%2JOd^%S{EqP55^M;JWs za7&rxOb~)EjU}e7##kEopJB=L5aT~R8=%K$+cP218B0M#FbsIea{J)#3!$eW?o3~8 zHKb`=`yZhPjo6PKf3yNf3Ozd%KvFiZsAl%Ej!wG@BCpoPS75tPO=!m(r`cSM9o~wI zXXsN+3vi%UgPA{a4VT7eAT|@|Tpr+oXhQgA^I21t>24@~$uZCvI6;a5g{C1p|JKVa zY{(tDABHdnfWV0qPg?QbNAW!m<9q&a=)u{qep-s}DaS{w_(;ip>x~%2VOqhR#mM#y zNSdL&P@;Q)_~pfA%pZO!c|k3&0rv*l?INkf+ir%KESYqec0(QQL6Sm(T45S;C?*du$9`GNrx50n7B*Mkou~$z8Y0>e3FYf%1tAX=Nu*kua6oZP+ z=V}ZcsPQQieVq?Cfq3;~%jH4C(`u_kV%x&`qgsu027`#7wBVa`5!N79a zd7a8CRg4Q&7g(5@fyi8jVEuyZbqct_27sq~Vcv$2x1%yd$vIh`AN?=p2XDm&8O3S# zAwf`Q(xF=DAM)g=qQ1T1k|+ZHIDAGQkRbAFQO=O>K>d5rIiPy97Uuq1K`*y>wCSaq zOL60SZg5{^&nlY861O72sC6mG!I6A_9|;^np5^uv3gYv+LTxhHB$|1fLzrX!BG#Cxb6aW;se`PZS!_G!znTW-R$xwhjKYsYT1j=fc~7H=Jmm#;4h^LaB1qjwrKm1=g5?t1&t30SnjP zK%Uou*xWSJG(CbUi2#A?bn56)N7ZfYT=HCk<2UBN^RG0%AIJF{kWJ9-`T&pTQ$4wR z;tAG1tu{qSVn;E&mguw+{pG}fl^7^S*7<1D@H%-8`8G~s?UvMa=TcePYe{<{jBniu zVSKbA#y*j5NH>4H)Uw=CY^jJ%pNKcaCAd)+n=4YHBE{CkxFx<)7P~C5t0Z>$Zreq; zac?;qvDVSxm58F}ptwkiCjlKn(u>4%J`~+JBX|`uCV}`}O*D*4a!IR*Ighk$!=gua zkx2VGKM)2T0(l}p@w!~CV71P~I44}l*yW3bBP^IC6y1Z}(jp_(Ct(f@n{PY`yEDlN<-jY)p$6p0Jju&uM2m_$Rq)U+e$? literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_generator.cpython-311.pyc b/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_generator.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ff339cc9f340345408ea98472facbad504aeb872 GIT binary patch literal 3551 zcma)8>uVfU6u)$GrPTa zw$-qKPzs$$kWGms9~6p6Mf$;iWg`nN1A&5ykI*l)r!aLT!nJ{DD7Sk=&1sN%&YMDp6^POp^&hi7Kd}5}g(%1WE+*9#O?xM3pph zFGR?Fc$_j3Qp2~%gs64^N_IaP`b9KhTfeZ{d68tI>o_b!ExEunO)qK2I&~{9Y1}xa za4qjl>>xH`*%$>_CK{QbDwz;e3hN5?x*=Q__cjq$CBP1?V?tIbtQEGx1$&9{yf+O_ zCBV}K&&G2A%cMqYBnMwksR{7s_g2Y8@(Uf$2$ra@0=LAgH&mVpSt8d;R~WL&q5vG( zNT<_JrcS+?{g`WvXU{2<#YrVwu4wwja+T$^?AemSua11GO^%FJDkGPwMwu0rQg-yZ zreDvVFHUB8(a=UJO8%-+(0JCP=db~^a2sJpddBrPC}9FDt~V`b?+0b@;|!{3QU`b)t8nFds67 zmfUFy=IMp^8}j~@Nz^@PyAO|3z_5JMYUD1C-cf=hX2CR>Py<^w zP^WIWNgbjkhErHTp^>jLrs;+it|-o%-zXaSFRl1Rqg;6(L{f}mS$9=og_*{yB_p5> z;6m5F3R;s>u?rUAuK>)EwbZ_5Dzln8)Jz=$vx>HQ`j!Xp3@#2W4VmFqw5v^MWKV0? zfce2+iNS_EXw#O7psDK0w3f?Row?j}S*@1vJC@5`t12a@h4sSFA(1)-Wz!GsA z49(e|&Nd!~y0HQE%s&B`^RHICXYOoU5Tt=N@j(`(=keDCnMz66tq0+-w6{%s=q9n` z+-ba=C2_TYnTb$gYyVI9_}d zwnMfX=CC@8yr^?S(es+E9xL`yRX2*$+8M^m%u(_HbcBd1T~|s~&7y^X9ZH|!BJ2S4 z*#{4w1^~m8yPNXhsyx(`hvvrC68$SZKb&1n>~ALaw@FCqYei$`@wMK4jo~*|dyh4H zk2PY)TCw=TIg>u_AYB97y0>K_g>Rj^ec|SX`k7U6PgC5}@a~{OJmgGr zg{t(HtO^FydL?+|f&1by6dKQa?fCYzxRHXN@95^4wggkcsfI&@Cwn(z{fSaJuax-7 z(f7RYKb{fU5R7I>5gSIp@Cv7@c%`c6?HD)bMA?Wxh-IM5i|}w<_@6EQlIS%*g)j@3 zWA2CSxorJG$iR@yu*%lc7jEo~`1@loL)$@Ye+vNSZ3|TDL+5%ne0TOCwmrKf*|H6T19S8HGDik2` z`jO6n6$ZnE>zGn7xxvVU5qks860IvB;x^v~Ar8#adExFB8eo`Pwi7~0FoFfe20;#P zO#&pQ=mpIRD-}qA9ES#7QQe|NOrJE}O`04#WiP;@GcN`;If|*zmZZmbgu<)Po1X*# zb6e}%vvPFt^3r7p?{N(I@qs#RbtjjjccLp}i;1N~J+ao^S63G0CAkh)Tk`tZ_O^~% zUPmX-bTZVL14tx8Shwqr;qU7ntlO=};TJp+?VlY*zyM)I6%HAoaR$$}jN~LgD4j)f z7M)_R!6(PnAYV+s<2Y#|DCo@4fAVkyXIKFM;agojrq~uk5fFSQJeEm3RafTEFPt~& zT2HEeZLxo;A1I0p+hC5h`cm}|q59I&CGgldR0Hgwubya!p#Fgz`(5t;P3~Vwu3T&E zA9L>2;jvZu-KP9*!@F%-pAw@mK5Re8F|B6^hvDHEo;CwhTZl@hXq!A8omhoK$K4~y zA`FRjk^?+J9M#xMVEk}KVDkAyKH;PxC)wNZi{{UN1pqNAeL#j9!TSM8HG+3r?4yuC r>;&`jL#%zY*>ogK2O+ocpf^MzF8a_NqbTCju?~}A%cEzs+XDRyD`Cv| literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_generator_nested.cpython-311.pyc b/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_generator_nested.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d27f1d34c6f1dc1e16d6f742560ea2829dffde05 GIT binary patch literal 9405 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 Mu=bm6nz)$!4-%O?dH?_b literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_greenlet.cpython-311.pyc b/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_greenlet.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a5a1cb56298635345687da84e3f13c1604cb15d5 GIT binary patch literal 74874 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_greenlet_trash.cpython-311.pyc b/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_greenlet_trash.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..779a8a2ad6fa2125e744f5613faffc41476e0e53 GIT binary patch literal 7305 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_leaks.cpython-311.pyc b/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_leaks.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eb82fd30f100f462e3d75ed4ccdc8aeeeefe3e8a GIT binary patch literal 22613 zcmeHvYit|Wdf*IS8j?eEWK-{lNm;T*+mdbhsl+c?4_mS=C$`+{C~g^=L&>!D@SUMz zn^#KJyY8BDwKq!Yz`nZ)s*CI7+D+1Rx4nRO(H~8>Khno8W{4?7%tC;HU84xFSjcb! zWH0u|e%~3+kTawlyGgM?v4@8rhcjo+oX2;*_nBY$d>#tYKi+$bU)M`f{~iD6$(cKN zc7mp;I}}e1Q#{Sv#^`a|ux;EvY#(IOc{qa?HSS`EWTocEj=7;k7j7#;1D5 zoa5_;*U{93cLNm4bOdhlZO?Rao39=#mr+dW@l1!23o z=8BM*NJd7cCSu9N*vUJxh8rjqeUV*JXakW?8y@peLlOM_owyTY`};4`|TVjPbB zBhkc|7{OX&7vr(ZaH>2pIx#84%_nP4pB)_RA3Pd4H5fVCKXmNukw{nfQ2(jHGjK1ADRWKce=zCP8R`K&74jf)CqNhZr9l5z3*kh|LHFe>2kk%K5Wm zToBJ6i(W`vh@PLk5}!CTIVHs6=ljN@;^np<#V@pVUAfXWG?knb649~q?Qh2?-adaK zapAm}NXFZ)z#v6OIAs(L?izl}w0X0Md2~LRZSFWo}B$Aj&BqNbj^K*u{T`v{F zCUyXrrIy##+}-frtG8cGJLZ`z!zxU}5);ZWp^uvuhkns|uT^HYD9jc~&(Gj4DrSs0 z{4wTg2>#rGQN4skNLnl`r=O&fI(dRKFER%L2L;1+VJ-ZqE+IZX`F30gz@G=SfK)=n zrv!ycyj&KE@bNJihYimk2U4gRZ*BoFOX)pt&M?g%pT6(-#kqUuWTstV+9f>;)lkyZ za|fItSh@=ifXvb+JhfmKjEgZEBes-_0_+Og22-v3pVQJH(3S1iTCN3Kgo9xl=`_JF z0jXADzX1V+_!Z&15kM=o5pNFxfS&t1m)SMx| zYea3*>wR$WBJ*t~2HLvP=G3OmsWS$|O#o_SkBy0iy>bGLizic|=ZsK0DY6;+(?I(3 znDHu1{SwoZVVY#7Sz($bJ(Io+hCR4kCZglEL?Fsp1e583r%q50Yxe%2q>(@GgLEH*)Vv-hG1xS-=BlyvUJ<*|?8q zi|z+r%mYuh)ar+`Yl_Ztynncy=b)~&@pXK8(e(gd#jk~@R>0MDMOQ1~Y@q0D6<+}h ztXg#=D?I_sQ#7qzgKGT`GAukjV_LoWwQA)zGqytdmFG7&lx7YxV^5YD(*WXw`DzdK z+w6?PMorr`TAB&D(;G+jqVPo>zk?lpGB+$7Lv3>v8WGp%+ z9)ts}=pJZ5jsi%v2R>?5YTM-6Z3^Z+O6`G1NvXDHR$HiF@lY0|5xaO@RK3tNs4+G< zHIWo{zy;MQL?=e$0@8HV3oAV?BzuuAfE<9_M%axP{Q5nS3-J*U#Z-D!r6VHFS`d@Q zjeMp?r>a)z4L(*(0YGZpn074JHhj44ezVs8wEqbkP}qhn+as|(Pwlj?kN%oMn5LhU zR{}w)ygT~YQqvSP=ca(oB1jrzJJCJh;PfI5bsEUV0VxH z84c*q0s0r*uRjOSzd(4qWGoQt0)>TE3jLjfv3yOM)PhX(*)ag$2j_VjnoeQU2|pKF zp*~?d0Fl1UHBq0nAcT!{Lw4DGl4@h7JXDr_yj(Y8Zh0 zmwU9|9EJ;fq5M}!07!GfE`r&@D|iC&T6h%!@^7INK-i&SHZFhR0D^-6L?lajT=o-O z&bKsGvuY=>cJV3zz~}OHX_t<`0}?xc2z-Jd@ChpduSW!4Zy>P5HbP!_Tl>|Z8JR2P zn(a!>_J<*v*`+YMBt2`$49_)`vW9e`Om$`fneq9*04vJL*@|9S8_`w7Wn7JRxvowMm*YYquA++*vkgGIBt4Uvc>oI|3F`s~?@=iG71}X?9J{qjL9AJrp+>1&&a`uc23%y!q_qUW>@t(oJmH+CKeNacGxlkFY4T~sRw#!{yeJi8 z;XC&EBS~+*;3Z@ZBo)<3Ef&Z;dMU~x2Es~tq1uwDOXt!hgZNvY`C@g=If3!4pK$pl~nyqVbK1k#!%WA}-Agl2j9DG3Eq2{Q?qRR0^Ay3RtU}=)^yoOktg^kkG zDW~d+UI7CGua;c}ffqy+)eb--{;2K)OR|lQ5)ErsQ&(^yrMBjm2_f>@LX7jozK|ES zv^D-)aEFML=i6E8F}vp7{#*SYjNZQdajVj_TW;E`H0_lu_bHY8WVTabJ0(4n6(MxP zeZp}BNGcw9HI_7pCr%-F4Z-UOP$m+v&1zl5XkO7GhVI1Fve@LZ#-I)KTRWp#6$d_0AM7tK7ZN< zI-UC!)S9i}8yB^*!qn ze1Ezh|McDJTj-b@m>)!W|&5q2`WrbVuF?e%M1{u zId+~+vz9Bsnvv#hAON4tEwK$5w&8B{ZuIA|4`VXhq_9mA$t!lf;Qyy=FyV#Cyj1^1 zQnprLSs&0hZOF8)(YI_bq8>&JfhldvF*%cXRD#L1n%UqbW0b8%!qRNZIuY~XIeTd_ zE9o<;rY;%m>P32GroHBWISI>d)-#a9683=9;^ov)w3E|i}G)mB>H(Kkgw%3JWy-~faH%`d&m90yFl%hx$O$KUD9)&{D+x* zD+L}KomWdpAAW@A&H(_mB#y_ZjA$hZ-Nq3GqFu(!RcU5h`V6Lm-! Seu!Bl_BRU2H$Z1g4q|M6A{dR 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 AdjJ3c literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_throw.cpython-311.pyc b/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_throw.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1492b72a0bb9350be7c4bab7fb9e47cfb76b0e62 GIT binary patch literal 8944 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_tracing.cpython-311.pyc b/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_tracing.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d694731a32de874ec93b4b3bfb1a6c1c0fe01f31 GIT binary patch literal 15408 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%0Auk}|;l zxRIl2lKNvtG3VodCe!hY*=&3wXBkveGO5HO(HB!!wCR+oStOoS((}qJF;laY5IsYz zGZrh4E|nMS1v8O--RWibA*;rMrYn}F&${vDhgwT&f@yj>!xWzO-&%TS<;|5X)egm~q1X<>!TwtKSgGrN?_+D1w|kD>9@@OHap99^J|6n?!bcar zIA_O(tFd9b=ecUnb89bbAMM+EW_{}R)DH3o2V7FZwa5BOlUvGqvc%OQ{iVe+xBj=X zTAsASr%S?ir0;$I`+>4riJUHp?(DX93jz>Qsq8|5XFSh*}*Z9Z{bSEd1HmQe>?bK!h+A!l0AX%aPZR@9h@ zT9Bed^dSaBM&t2Das~sm7wkEbIj?2ePa9<)06^+>)9ED3B%QOEb;_!#BW4*u9Dx!= zbwt>!Wt}d?1>@z{a!SULnlNy>mnPJl;nHlp?^8bdL?{$EwCL7-TF%@V+Ui^AcJbhsq$;JaAb3FV{v`?_VVV+#)=(2 zSq-0D8)cRlP8#HA#y#++zb@?Im=6c-@}Z94zof_yQe-Rg$+>E5$d=AkrE`_$W1fI( z`$yMdwBC8KlYj5{MUnqn6oLKv?8)a(@ZX#eo`1^!O&kLq8x&ZHV&w!%RHrO27;4Tf zR{>dOIH<4CGhp#EM4y1c%^+p9$0h7%$&3M6_4*EXO#J;0+E42GOm(o69X6A*aug1x z?AL_~j0`a1B2>!hn#FKJ+21DT$e5vDA<8^d9ENT7zmJ||n_W-NGS2hvp)_2NV}uUD z0{g8q-vR=8!1z8oQE7i_=y;|5xsN(m-Cjc-t8TBMvz7MeJ_@b6eMjoY5bl0b={f#0 L6F)d$&2{#FxD~VR literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_weakref.cpython-311.pyc b/.venv/Lib/site-packages/greenlet/tests/__pycache__/test_weakref.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a6f0d739cc7e3a92fa21442b31ac8c17bf6a771f GIT binary patch literal 3116 zcmb_e+iTla7(cq$Q5-o{nxyk?ozt{gz2?GJI>soaCTtDqNZH!aEf_q-I&qySwkIjc z7E&-

_zg3`Sh&AP*yJ>D&H;{ReRo)QA-ddl-H5$O@rP`@SPfjqGOkBk89jpL4$R z-Olgx57B6ZK>PLk&$O=uLVm#yuZ5bOohj&S5RGV@PNv;AH_fqcewt@*VOr35P0+=K z&~%6+JUK@+@fy)WG_(bB@4@4?>9EFKB#H22{G58s0VX&{xV!6lP|;)hI!P2UXbF0svD$!d1@NGh@#0 z^JJC7S@+;^+ZK%7^T)69mgg84p7RY0uHnck*~DGj8p!8^b2YNX!w&GcjRO~hJ^WO_ z8Msj|JUgENY>|GOBK#8Fhd5!$6KyMzJ4Z{zkfEF49m!kagw5rgmAL{b%4JRT zM%;)3I^99ZD{uchjqvc9LjWc6P>I>fz~=Dga7`Jrm9cWNE=O-ntW8uV*C)%9_1?bn zgsWf3>1cYz5x_MLpUpTOnS!p*uT8)$UsCxE(uQlM}X_D02^`$ab>1t)oRk9Ee&paH#6_~=k`a~wI%8Oqz;@%{}ct&yX8=DRtE@d zwmJWt2G_7NyyvWY^9j&fD@Q#43>z5VMA*P1Wb`2%KbcJO==2CHJnM|4y=FiCXN09XnBzhi!TI{|ih5cDXKG z7dJ?jtchizEY2c9OD*&Yv)l%bgTOtb(>0+Y{5^i!hw-2cRD>Xb?nlu;ye)fcd-#EJ z^1gDirkt{sQ`^d^M@rvD*Ee0&WHotf{PuWFiQ7ti+q-vfiu;Z3?(Ujc8@_%cDU+Y% z*ODiMKrzOMw$w%D8&(%xz*54@HM*gQ$#WENoV%O{>(bPOkTvr}yv*Ba)Cy zB!jRFio#pW{l*a#f-DBafA*{!fIg4<_xgHe;4f9gUCcFrUGRVXKu=k0@M7mcgX{xO zA|%>x%db{vYw|H$K33-HQs)h6O{zduC`TT`VDxZxwYqxe!&-FAj*gXi##dFoa$)@f z%#QYy`Db;bZ&R!;)ubU?8rt@5Rx_p&VMj`*^XdXkr=3VTy-?5=b?nROG*&`)#CQo* zH(o&)Lcj>K^=_Q-7#j!@JZ2K0D|gDV|nCOTZ&$E= 3 +# define INITERROR return NULL + +static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, + TEST_MODULE_NAME, + NULL, + 0, + test_methods, + NULL, + NULL, + NULL, + NULL}; + +PyMODINIT_FUNC +PyInit__test_extension(void) +#else +# define INITERROR return +PyMODINIT_FUNC +init_test_extension(void) +#endif +{ + PyObject* module = NULL; + +#if PY_MAJOR_VERSION >= 3 + module = PyModule_Create(&moduledef); +#else + module = Py_InitModule(TEST_MODULE_NAME, test_methods); +#endif + + if (module == NULL) { + INITERROR; + } + + PyGreenlet_Import(); + +#if PY_MAJOR_VERSION >= 3 + return module; +#endif +} diff --git a/.venv/Lib/site-packages/greenlet/tests/_test_extension.cp311-win_amd64.pyd b/.venv/Lib/site-packages/greenlet/tests/_test_extension.cp311-win_amd64.pyd new file mode 100644 index 0000000000000000000000000000000000000000..f3ec6fbef5be64c080f820da1af9aef7d5186da1 GIT binary patch literal 13312 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/greenlet/tests/_test_extension_cpp.cp311-win_amd64.pyd b/.venv/Lib/site-packages/greenlet/tests/_test_extension_cpp.cp311-win_amd64.pyd new file mode 100644 index 0000000000000000000000000000000000000000..2f144c5999664867db65f2c063cf6aaae92b6313 GIT binary patch literal 13824 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/greenlet/tests/_test_extension_cpp.cpp b/.venv/Lib/site-packages/greenlet/tests/_test_extension_cpp.cpp new file mode 100644 index 000000000..d4dfd5eb8 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/tests/_test_extension_cpp.cpp @@ -0,0 +1,196 @@ +/* This is a set of functions used to test C++ exceptions are not + * broken during greenlet switches + */ + +#include "../greenlet.h" +#include "../greenlet_compiler_compat.hpp" + +struct exception_t { + int depth; + exception_t(int depth) : depth(depth) {} +}; + +/* Functions are called via pointers to prevent inlining */ +static void (*p_test_exception_throw)(int depth); +static PyObject* (*p_test_exception_switch_recurse)(int depth, int left); + +static void +test_exception_throw(int depth) +{ + throw exception_t(depth); +} + +static PyObject* +test_exception_switch_recurse(int depth, int left) +{ + if (left > 0) { + return p_test_exception_switch_recurse(depth, left - 1); + } + + PyObject* result = NULL; + PyGreenlet* self = PyGreenlet_GetCurrent(); + if (self == NULL) + return NULL; + + try { + if (PyGreenlet_Switch(PyGreenlet_GET_PARENT(self), NULL, NULL) == NULL) { + Py_DECREF(self); + return NULL; + } + p_test_exception_throw(depth); + PyErr_SetString(PyExc_RuntimeError, + "throwing C++ exception didn't work"); + } + catch (const exception_t& e) { + if (e.depth != depth) + PyErr_SetString(PyExc_AssertionError, "depth mismatch"); + else + result = PyLong_FromLong(depth); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "unexpected C++ exception"); + } + + Py_DECREF(self); + return result; +} + +/* test_exception_switch(int depth) + * - recurses depth times + * - switches to parent inside try/catch block + * - throws an exception that (expected to be caught in the same function) + * - verifies depth matches (exceptions shouldn't be caught in other greenlets) + */ +static PyObject* +test_exception_switch(PyObject* UNUSED(self), PyObject* args) +{ + int depth; + if (!PyArg_ParseTuple(args, "i", &depth)) + return NULL; + return p_test_exception_switch_recurse(depth, depth); +} + + +static PyObject* +py_test_exception_throw(PyObject* self, PyObject* args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + p_test_exception_throw(0); + PyErr_SetString(PyExc_AssertionError, "unreachable code running after throw"); + return NULL; +} + + +/* test_exception_switch_and_do_in_g2(g2func) + * - creates new greenlet g2 to run g2func + * - switches to g2 inside try/catch block + * - verifies that no exception has been caught + * + * it is used together with test_exception_throw to verify that unhandled + * exceptions thrown in one greenlet do not propagate to other greenlet nor + * segfault the process. + */ +static PyObject* +test_exception_switch_and_do_in_g2(PyObject* self, PyObject* args) +{ + PyObject* g2func = NULL; + PyObject* result = NULL; + + if (!PyArg_ParseTuple(args, "O", &g2func)) + return NULL; + PyGreenlet* g2 = PyGreenlet_New(g2func, NULL); + if (!g2) { + return NULL; + } + + try { + result = PyGreenlet_Switch(g2, NULL, NULL); + if (!result) { + return NULL; + } + } + catch (const exception_t& e) { + /* if we are here the memory can be already corrupted and the program + * might crash before below py-level exception might become printed. + * -> print something to stderr to make it clear that we had entered + * this catch block. + * See comments in inner_bootstrap() + */ +#if defined(WIN32) || defined(_WIN32) + fprintf(stderr, "C++ exception unexpectedly caught in g1\n"); + PyErr_SetString(PyExc_AssertionError, "C++ exception unexpectedly caught in g1"); + Py_XDECREF(result); + return NULL; +#else + throw; +#endif + } + + Py_XDECREF(result); + Py_RETURN_NONE; +} + +static PyMethodDef test_methods[] = { + {"test_exception_switch", + (PyCFunction)&test_exception_switch, + METH_VARARGS, + "Switches to parent twice, to test exception handling and greenlet " + "switching."}, + {"test_exception_switch_and_do_in_g2", + (PyCFunction)&test_exception_switch_and_do_in_g2, + METH_VARARGS, + "Creates new greenlet g2 to run g2func and switches to it inside try/catch " + "block. Used together with test_exception_throw to verify that unhandled " + "C++ exceptions thrown in a greenlet doe not corrupt memory."}, + {"test_exception_throw", + (PyCFunction)&py_test_exception_throw, + METH_VARARGS, + "Throws C++ exception. Calling this function directly should abort the process."}, + {NULL, NULL, 0, NULL}}; + +#if PY_MAJOR_VERSION >= 3 +# define INITERROR return NULL + +static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, + "greenlet.tests._test_extension_cpp", + NULL, + 0, + test_methods, + NULL, + NULL, + NULL, + NULL}; + +PyMODINIT_FUNC +PyInit__test_extension_cpp(void) +#else +# define INITERROR return +PyMODINIT_FUNC +init_test_extension_cpp(void) +#endif +{ + PyObject* module = NULL; + +#if PY_MAJOR_VERSION >= 3 + module = PyModule_Create(&moduledef); +#else + module = Py_InitModule("greenlet.tests._test_extension_cpp", test_methods); +#endif + + if (module == NULL) { + INITERROR; + } + + PyGreenlet_Import(); + if (_PyGreenlet_API == NULL) { + INITERROR; + } + + p_test_exception_throw = test_exception_throw; + p_test_exception_switch_recurse = test_exception_switch_recurse; + +#if PY_MAJOR_VERSION >= 3 + return module; +#endif +} diff --git a/.venv/Lib/site-packages/greenlet/tests/leakcheck.py b/.venv/Lib/site-packages/greenlet/tests/leakcheck.py new file mode 100644 index 000000000..79a18fcef --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/tests/leakcheck.py @@ -0,0 +1,318 @@ +# Copyright (c) 2018 gevent community +# Copyright (c) 2021 greenlet community +# +# This was originally part of gevent's test suite. The main author +# (Jason Madden) vendored a copy of it into greenlet. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +from __future__ import print_function + +import os +import sys +import gc + +from functools import wraps +import unittest + + +import objgraph + +# graphviz 0.18 (Nov 7 2021), available only on Python 3.6 and newer, +# has added type hints (sigh). It wants to use ``typing.Literal`` for +# some stuff, but that's only available on Python 3.9+. If that's not +# found, it creates a ``unittest.mock.MagicMock`` object and annotates +# with that. These are GC'able objects, and doing almost *anything* +# with them results in an explosion of objects. For example, trying to +# compare them for equality creates new objects. This causes our +# leakchecks to fail, with reports like: +# +# greenlet.tests.leakcheck.LeakCheckError: refcount increased by [337, 1333, 343, 430, 530, 643, 769] +# _Call 1820 +546 +# dict 4094 +76 +# MagicProxy 585 +73 +# tuple 2693 +66 +# _CallList 24 +3 +# weakref 1441 +1 +# function 5996 +1 +# type 736 +1 +# cell 592 +1 +# MagicMock 8 +1 +# +# To avoid this, we *could* filter this type of object out early. In +# principle it could leak, but we don't use mocks in greenlet, so it +# doesn't leak from us. However, a further issue is that ``MagicMock`` +# objects have subobjects that are also GC'able, like ``_Call``, and +# those create new mocks of their own too. So we'd have to filter them +# as well, and they're not public. That's OK, we can workaround the +# problem by being very careful to never compare by equality or other +# user-defined operators, only using object identity or other builtin +# functions. + +RUNNING_ON_GITHUB_ACTIONS = os.environ.get('GITHUB_ACTIONS') +RUNNING_ON_TRAVIS = os.environ.get('TRAVIS') or RUNNING_ON_GITHUB_ACTIONS +RUNNING_ON_APPVEYOR = os.environ.get('APPVEYOR') +RUNNING_ON_CI = RUNNING_ON_TRAVIS or RUNNING_ON_APPVEYOR +RUNNING_ON_MANYLINUX = os.environ.get('GREENLET_MANYLINUX') +SKIP_LEAKCHECKS = RUNNING_ON_MANYLINUX or os.environ.get('GREENLET_SKIP_LEAKCHECKS') +SKIP_FAILING_LEAKCHECKS = os.environ.get('GREENLET_SKIP_FAILING_LEAKCHECKS') +ONLY_FAILING_LEAKCHECKS = os.environ.get('GREENLET_ONLY_FAILING_LEAKCHECKS') + +def ignores_leakcheck(func): + """ + Ignore the given object during leakchecks. + + Can be applied to a method, in which case the method will run, but + will not be subject to leak checks. + + If applied to a class, the entire class will be skipped during leakchecks. This + is intended to be used for classes that are very slow and cause problems such as + test timeouts; typically it will be used for classes that are subclasses of a base + class and specify variants of behaviour (such as pool sizes). + """ + func.ignore_leakcheck = True + return func + +def fails_leakcheck(func): + """ + Mark that the function is known to leak. + """ + func.fails_leakcheck = True + if SKIP_FAILING_LEAKCHECKS: + func = unittest.skip("Skipping known failures")(func) + return func + +class LeakCheckError(AssertionError): + pass + +if hasattr(sys, 'getobjects'): + # In a Python build with ``--with-trace-refs``, make objgraph + # trace *all* the objects, not just those that are tracked by the + # GC + class _MockGC(object): + def get_objects(self): + return sys.getobjects(0) # pylint:disable=no-member + def __getattr__(self, name): + return getattr(gc, name) + objgraph.gc = _MockGC() + fails_strict_leakcheck = fails_leakcheck +else: + def fails_strict_leakcheck(func): + """ + Decorator for a function that is known to fail when running + strict (``sys.getobjects()``) leakchecks. + + This type of leakcheck finds all objects, even those, such as + strings, which are not tracked by the garbage collector. + """ + return func + +class ignores_types_in_strict_leakcheck(object): + def __init__(self, types): + self.types = types + def __call__(self, func): + func.leakcheck_ignore_types = self.types + return func + +class _RefCountChecker(object): + + # Some builtin things that we ignore + # XXX: Those things were ignored by gevent, but they're important here, + # presumably. + IGNORED_TYPES = () #(tuple, dict, types.FrameType, types.TracebackType) + + def __init__(self, testcase, function): + self.testcase = testcase + self.function = function + self.deltas = [] + self.peak_stats = {} + self.ignored_types = () + + # The very first time we are called, we have already been + # self.setUp() by the test runner, so we don't need to do it again. + self.needs_setUp = False + + def _include_object_p(self, obj): + # pylint:disable=too-many-return-statements + # + # See the comment block at the top. We must be careful to + # avoid invoking user-defined operations. + if obj is self: + return False + kind = type(obj) + # ``self._include_object_p == obj`` returns NotImplemented + # for non-function objects, which causes the interpreter + # to try to reverse the order of arguments...which leads + # to the explosion of mock objects. We don't want that, so we implement + # the check manually. + if kind == type(self._include_object_p): + try: + # pylint:disable=not-callable + exact_method_equals = self._include_object_p.__eq__(obj) + except AttributeError: + # Python 2.7 methods may only have __cmp__, and that raises a + # TypeError for non-method arguments + # pylint:disable=no-member + exact_method_equals = self._include_object_p.__cmp__(obj) == 0 + + if exact_method_equals is not NotImplemented and exact_method_equals: + return False + + # Similarly, we need to check identity in our __dict__ to avoid mock explosions. + for x in self.__dict__.values(): + if obj is x: + return False + + + if kind in self.ignored_types or kind in self.IGNORED_TYPES: + return False + + return True + + def _growth(self): + return objgraph.growth(limit=None, peak_stats=self.peak_stats, + filter=self._include_object_p) + + def _report_diff(self, growth): + if not growth: + return "" + + lines = [] + width = max(len(name) for name, _, _ in growth) + for name, count, delta in growth: + lines.append('%-*s%9d %+9d' % (width, name, count, delta)) + + diff = '\n'.join(lines) + return diff + + + def _run_test(self, args, kwargs): + gc_enabled = gc.isenabled() + gc.disable() + + if self.needs_setUp: + self.testcase.setUp() + self.testcase.skipTearDown = False + try: + self.function(self.testcase, *args, **kwargs) + finally: + self.testcase.tearDown() + self.testcase.doCleanups() + self.testcase.skipTearDown = True + self.needs_setUp = True + if gc_enabled: + gc.enable() + + def _growth_after(self): + # Grab post snapshot + if 'urlparse' in sys.modules: + sys.modules['urlparse'].clear_cache() + if 'urllib.parse' in sys.modules: + sys.modules['urllib.parse'].clear_cache() + + return self._growth() + + def _check_deltas(self, growth): + # Return false when we have decided there is no leak, + # true if we should keep looping, raises an assertion + # if we have decided there is a leak. + + deltas = self.deltas + if not deltas: + # We haven't run yet, no data, keep looping + return True + + if gc.garbage: + raise LeakCheckError("Generated uncollectable garbage %r" % (gc.garbage,)) + + + # the following configurations are classified as "no leak" + # [0, 0] + # [x, 0, 0] + # [... a, b, c, d] where a+b+c+d = 0 + # + # the following configurations are classified as "leak" + # [... z, z, z] where z > 0 + + if deltas[-2:] == [0, 0] and len(deltas) in (2, 3): + return False + + if deltas[-3:] == [0, 0, 0]: + return False + + if len(deltas) >= 4 and sum(deltas[-4:]) == 0: + return False + + if len(deltas) >= 3 and deltas[-1] > 0 and deltas[-1] == deltas[-2] and deltas[-2] == deltas[-3]: + diff = self._report_diff(growth) + raise LeakCheckError('refcount increased by %r\n%s' % (deltas, diff)) + + # OK, we don't know for sure yet. Let's search for more + if sum(deltas[-3:]) <= 0 or sum(deltas[-4:]) <= 0 or deltas[-4:].count(0) >= 2: + # this is suspicious, so give a few more runs + limit = 11 + else: + limit = 7 + if len(deltas) >= limit: + raise LeakCheckError('refcount increased by %r\n%s' + % (deltas, + self._report_diff(growth))) + + # We couldn't decide yet, keep going + return True + + def __call__(self, args, kwargs): + for _ in range(3): + gc.collect() + + expect_failure = getattr(self.function, 'fails_leakcheck', False) + if expect_failure: + self.testcase.expect_greenlet_leak = True + self.ignored_types = getattr(self.function, "leakcheck_ignore_types", ()) + + # Capture state before; the incremental will be + # updated by each call to _growth_after + growth = self._growth() + + try: + while self._check_deltas(growth): + self._run_test(args, kwargs) + + growth = self._growth_after() + + self.deltas.append(sum((stat[2] for stat in growth))) + except LeakCheckError: + if not expect_failure: + raise + else: + if expect_failure: + raise LeakCheckError("Expected %s to leak but it did not." % (self.function,)) + +def wrap_refcount(method): + if getattr(method, 'ignore_leakcheck', False) or SKIP_LEAKCHECKS: + return method + + @wraps(method) + def wrapper(self, *args, **kwargs): # pylint:disable=too-many-branches + if getattr(self, 'ignore_leakcheck', False): + raise unittest.SkipTest("This class ignored during leakchecks") + if ONLY_FAILING_LEAKCHECKS and not getattr(method, 'fails_leakcheck', False): + raise unittest.SkipTest("Only running tests that fail leakchecks.") + return _RefCountChecker(self, method)(args, kwargs) + + return wrapper diff --git a/.venv/Lib/site-packages/greenlet/tests/test_contextvars.py b/.venv/Lib/site-packages/greenlet/tests/test_contextvars.py new file mode 100644 index 000000000..38b9bb798 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/tests/test_contextvars.py @@ -0,0 +1,304 @@ +from __future__ import print_function + +import gc +import sys + +from functools import partial +from unittest import skipUnless +from unittest import skipIf + +from greenlet import greenlet +from greenlet import getcurrent +from . import TestCase + + +try: + from contextvars import Context + from contextvars import ContextVar + from contextvars import copy_context + # From the documentation: + # + # Important: Context Variables should be created at the top module + # level and never in closures. Context objects hold strong + # references to context variables which prevents context variables + # from being properly garbage collected. + ID_VAR = ContextVar("id", default=None) + VAR_VAR = ContextVar("var", default=None) + ContextVar = None +except ImportError: + Context = ContextVar = copy_context = None + +# We don't support testing if greenlet's built-in context var support is disabled. +@skipUnless(Context is not None, "ContextVar not supported") +class ContextVarsTests(TestCase): + def _new_ctx_run(self, *args, **kwargs): + return copy_context().run(*args, **kwargs) + + def _increment(self, greenlet_id, callback, counts, expect): + ctx_var = ID_VAR + if expect is None: + self.assertIsNone(ctx_var.get()) + else: + self.assertEqual(ctx_var.get(), expect) + ctx_var.set(greenlet_id) + for _ in range(2): + counts[ctx_var.get()] += 1 + callback() + + def _test_context(self, propagate_by): + ID_VAR.set(0) + + callback = getcurrent().switch + counts = dict((i, 0) for i in range(5)) + + lets = [ + greenlet(partial( + partial( + copy_context().run, + self._increment + ) if propagate_by == "run" else self._increment, + greenlet_id=i, + callback=callback, + counts=counts, + expect=( + i - 1 if propagate_by == "share" else + 0 if propagate_by in ("set", "run") else None + ) + )) + for i in range(1, 5) + ] + + for let in lets: + if propagate_by == "set": + let.gr_context = copy_context() + elif propagate_by == "share": + let.gr_context = getcurrent().gr_context + + for i in range(2): + counts[ID_VAR.get()] += 1 + for let in lets: + let.switch() + + if propagate_by == "run": + # Must leave each context.run() in reverse order of entry + for let in reversed(lets): + let.switch() + else: + # No context.run(), so fine to exit in any order. + for let in lets: + let.switch() + + for let in lets: + self.assertTrue(let.dead) + # When using run(), we leave the run() as the greenlet dies, + # and there's no context "underneath". When not using run(), + # gr_context still reflects the context the greenlet was + # running in. + if propagate_by == 'run': + self.assertIsNone(let.gr_context) + else: + self.assertIsNotNone(let.gr_context) + + + if propagate_by == "share": + self.assertEqual(counts, {0: 1, 1: 1, 2: 1, 3: 1, 4: 6}) + else: + self.assertEqual(set(counts.values()), set([2])) + + def test_context_propagated_by_context_run(self): + self._new_ctx_run(self._test_context, "run") + + def test_context_propagated_by_setting_attribute(self): + self._new_ctx_run(self._test_context, "set") + + def test_context_not_propagated(self): + self._new_ctx_run(self._test_context, None) + + def test_context_shared(self): + self._new_ctx_run(self._test_context, "share") + + def test_break_ctxvars(self): + let1 = greenlet(copy_context().run) + let2 = greenlet(copy_context().run) + let1.switch(getcurrent().switch) + let2.switch(getcurrent().switch) + # Since let2 entered the current context and let1 exits its own, the + # interpreter emits: + # RuntimeError: cannot exit context: thread state references a different context object + let1.switch() + + def test_not_broken_if_using_attribute_instead_of_context_run(self): + let1 = greenlet(getcurrent().switch) + let2 = greenlet(getcurrent().switch) + let1.gr_context = copy_context() + let2.gr_context = copy_context() + let1.switch() + let2.switch() + let1.switch() + let2.switch() + + def test_context_assignment_while_running(self): + # pylint:disable=too-many-statements + ID_VAR.set(None) + + def target(): + self.assertIsNone(ID_VAR.get()) + self.assertIsNone(gr.gr_context) + + # Context is created on first use + ID_VAR.set(1) + self.assertIsInstance(gr.gr_context, Context) + self.assertEqual(ID_VAR.get(), 1) + self.assertEqual(gr.gr_context[ID_VAR], 1) + + # Clearing the context makes it get re-created as another + # empty context when next used + old_context = gr.gr_context + gr.gr_context = None # assign None while running + self.assertIsNone(ID_VAR.get()) + self.assertIsNone(gr.gr_context) + ID_VAR.set(2) + self.assertIsInstance(gr.gr_context, Context) + self.assertEqual(ID_VAR.get(), 2) + self.assertEqual(gr.gr_context[ID_VAR], 2) + + new_context = gr.gr_context + getcurrent().parent.switch((old_context, new_context)) + # parent switches us back to old_context + + self.assertEqual(ID_VAR.get(), 1) + gr.gr_context = new_context # assign non-None while running + self.assertEqual(ID_VAR.get(), 2) + + getcurrent().parent.switch() + # parent switches us back to no context + self.assertIsNone(ID_VAR.get()) + self.assertIsNone(gr.gr_context) + gr.gr_context = old_context + self.assertEqual(ID_VAR.get(), 1) + + getcurrent().parent.switch() + # parent switches us back to no context + self.assertIsNone(ID_VAR.get()) + self.assertIsNone(gr.gr_context) + + gr = greenlet(target) + + with self.assertRaisesRegex(AttributeError, "can't delete context attribute"): + del gr.gr_context + + self.assertIsNone(gr.gr_context) + old_context, new_context = gr.switch() + self.assertIs(new_context, gr.gr_context) + self.assertEqual(old_context[ID_VAR], 1) + self.assertEqual(new_context[ID_VAR], 2) + self.assertEqual(new_context.run(ID_VAR.get), 2) + gr.gr_context = old_context # assign non-None while suspended + gr.switch() + self.assertIs(gr.gr_context, new_context) + gr.gr_context = None # assign None while suspended + gr.switch() + self.assertIs(gr.gr_context, old_context) + gr.gr_context = None + gr.switch() + self.assertIsNone(gr.gr_context) + + # Make sure there are no reference leaks + gr = None + gc.collect() + self.assertEqual(sys.getrefcount(old_context), 2) + self.assertEqual(sys.getrefcount(new_context), 2) + + def test_context_assignment_different_thread(self): + import threading + VAR_VAR.set(None) + ctx = Context() + + is_running = threading.Event() + should_suspend = threading.Event() + did_suspend = threading.Event() + should_exit = threading.Event() + holder = [] + + def greenlet_in_thread_fn(): + VAR_VAR.set(1) + is_running.set() + should_suspend.wait(10) + VAR_VAR.set(2) + getcurrent().parent.switch() + holder.append(VAR_VAR.get()) + + def thread_fn(): + gr = greenlet(greenlet_in_thread_fn) + gr.gr_context = ctx + holder.append(gr) + gr.switch() + did_suspend.set() + should_exit.wait(10) + gr.switch() + del gr + greenlet() # trigger cleanup + + thread = threading.Thread(target=thread_fn, daemon=True) + thread.start() + is_running.wait(10) + gr = holder[0] + + # Can't access or modify context if the greenlet is running + # in a different thread + with self.assertRaisesRegex(ValueError, "running in a different"): + getattr(gr, 'gr_context') + with self.assertRaisesRegex(ValueError, "running in a different"): + gr.gr_context = None + + should_suspend.set() + did_suspend.wait(10) + + # OK to access and modify context if greenlet is suspended + self.assertIs(gr.gr_context, ctx) + self.assertEqual(gr.gr_context[VAR_VAR], 2) + gr.gr_context = None + + should_exit.set() + thread.join(10) + + self.assertEqual(holder, [gr, None]) + + # Context can still be accessed/modified when greenlet is dead: + self.assertIsNone(gr.gr_context) + gr.gr_context = ctx + self.assertIs(gr.gr_context, ctx) + + # Otherwise we leak greenlets on some platforms. + # XXX: Should be able to do this automatically + del holder[:] + gr = None + thread = None + + def test_context_assignment_wrong_type(self): + g = greenlet() + with self.assertRaisesRegex(TypeError, + "greenlet context must be a contextvars.Context or None"): + g.gr_context = self + + +@skipIf(Context is not None, "ContextVar supported") +class NoContextVarsTests(TestCase): + def test_contextvars_errors(self): + let1 = greenlet(getcurrent().switch) + self.assertFalse(hasattr(let1, 'gr_context')) + with self.assertRaises(AttributeError): + getattr(let1, 'gr_context') + + with self.assertRaises(AttributeError): + let1.gr_context = None + + let1.switch() + + with self.assertRaises(AttributeError): + getattr(let1, 'gr_context') + + with self.assertRaises(AttributeError): + let1.gr_context = None + + del let1 diff --git a/.venv/Lib/site-packages/greenlet/tests/test_cpp.py b/.venv/Lib/site-packages/greenlet/tests/test_cpp.py new file mode 100644 index 000000000..7aaeb0bb4 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/tests/test_cpp.py @@ -0,0 +1,80 @@ +from __future__ import print_function +from __future__ import absolute_import + +import signal +from multiprocessing import Process + +import greenlet +from . import _test_extension_cpp +from . import TestCase + +def run_unhandled_exception_in_greenlet_aborts(): + # This is used in multiprocessing.Process and must be picklable + # so it needs to be global. + + + def _(): + _test_extension_cpp.test_exception_switch_and_do_in_g2( + _test_extension_cpp.test_exception_throw + ) + g1 = greenlet.greenlet(_) + g1.switch() + +class CPPTests(TestCase): + def test_exception_switch(self): + greenlets = [] + for i in range(4): + g = greenlet.greenlet(_test_extension_cpp.test_exception_switch) + g.switch(i) + greenlets.append(g) + for i, g in enumerate(greenlets): + self.assertEqual(g.switch(), i) + + def _do_test_unhandled_exception(self, target): + # TODO: On some versions of Python with some settings, this + # spews a lot of garbage to stderr. It would be nice to capture and ignore that. + import sys + WIN = sys.platform.startswith("win") + + p = Process(target=target) + p.start() + p.join(10) + # The child should be aborted in an unusual way. On POSIX + # platforms, this is done with abort() and signal.SIGABRT, + # which is reflected in a negative return value; however, on + # Windows, even though we observe the child print "Fatal + # Python error: Aborted" and in older versions of the C + # runtime "This application has requested the Runtime to + # terminate it in an unusual way," it always has an exit code + # of 3. This is interesting because 3 is the error code for + # ERROR_PATH_NOT_FOUND; BUT: the C runtime abort() function + # also uses this code. + # + # See + # https://devblogs.microsoft.com/oldnewthing/20110519-00/?p=10623 + # and + # https://docs.microsoft.com/en-us/previous-versions/k089yyh0(v=vs.140)?redirectedfrom=MSDN + expected_exit = ( + -signal.SIGABRT, + # But beginning on Python 3.11, the faulthandler + # that prints the C backtraces sometimes segfaults after + # reporting the exception but before printing the stack. + # This has only been seen on linux/gcc. + -signal.SIGSEGV + ) if not WIN else ( + 3, + ) + self.assertIn(p.exitcode, expected_exit) + + def test_unhandled_exception_aborts(self): + # verify that plain unhandled throw aborts + self._do_test_unhandled_exception(_test_extension_cpp.test_exception_throw) + + + def test_unhandled_exception_in_greenlet_aborts(self): + # verify that unhandled throw called in greenlet aborts too + self._do_test_unhandled_exception(run_unhandled_exception_in_greenlet_aborts) + + +if __name__ == '__main__': + __import__('unittest').main() diff --git a/.venv/Lib/site-packages/greenlet/tests/test_extension_interface.py b/.venv/Lib/site-packages/greenlet/tests/test_extension_interface.py new file mode 100644 index 000000000..34b66567f --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/tests/test_extension_interface.py @@ -0,0 +1,115 @@ +from __future__ import print_function +from __future__ import absolute_import + +import sys + +import greenlet +from . import _test_extension +from . import TestCase + +# pylint:disable=c-extension-no-member + +class CAPITests(TestCase): + def test_switch(self): + self.assertEqual( + 50, _test_extension.test_switch(greenlet.greenlet(lambda: 50))) + + def test_switch_kwargs(self): + def adder(x, y): + return x * y + g = greenlet.greenlet(adder) + self.assertEqual(6, _test_extension.test_switch_kwargs(g, x=3, y=2)) + + def test_setparent(self): + # pylint:disable=disallowed-name + def foo(): + def bar(): + greenlet.getcurrent().parent.switch() + + # This final switch should go back to the main greenlet, since + # the test_setparent() function in the C extension should have + # reparented this greenlet. + greenlet.getcurrent().parent.switch() + raise AssertionError("Should never have reached this code") + child = greenlet.greenlet(bar) + child.switch() + greenlet.getcurrent().parent.switch(child) + greenlet.getcurrent().parent.throw( + AssertionError("Should never reach this code")) + foo_child = greenlet.greenlet(foo).switch() + self.assertEqual(None, _test_extension.test_setparent(foo_child)) + + def test_getcurrent(self): + _test_extension.test_getcurrent() + + def test_new_greenlet(self): + self.assertEqual(-15, _test_extension.test_new_greenlet(lambda: -15)) + + def test_raise_greenlet_dead(self): + self.assertRaises( + greenlet.GreenletExit, _test_extension.test_raise_dead_greenlet) + + def test_raise_greenlet_error(self): + self.assertRaises( + greenlet.error, _test_extension.test_raise_greenlet_error) + + def test_throw(self): + seen = [] + + def foo(): # pylint:disable=disallowed-name + try: + greenlet.getcurrent().parent.switch() + except ValueError: + seen.append(sys.exc_info()[1]) + except greenlet.GreenletExit: + raise AssertionError + g = greenlet.greenlet(foo) + g.switch() + _test_extension.test_throw(g) + self.assertEqual(len(seen), 1) + self.assertTrue( + isinstance(seen[0], ValueError), + "ValueError was not raised in foo()") + self.assertEqual( + str(seen[0]), + 'take that sucka!', + "message doesn't match") + + def test_non_traceback_param(self): + with self.assertRaises(TypeError) as exc: + _test_extension.test_throw_exact( + greenlet.getcurrent(), + Exception, + Exception(), + self + ) + self.assertEqual(str(exc.exception), + "throw() third argument must be a traceback object") + + def test_instance_of_wrong_type(self): + with self.assertRaises(TypeError) as exc: + _test_extension.test_throw_exact( + greenlet.getcurrent(), + Exception(), + BaseException(), + None, + ) + + self.assertEqual(str(exc.exception), + "instance exception may not have a separate value") + + def test_not_throwable(self): + with self.assertRaises(TypeError) as exc: + _test_extension.test_throw_exact( + greenlet.getcurrent(), + "abc", + None, + None, + ) + self.assertEqual(str(exc.exception), + "exceptions must be classes, or instances, not str") + + +if __name__ == '__main__': + import unittest + unittest.main() diff --git a/.venv/Lib/site-packages/greenlet/tests/test_gc.py b/.venv/Lib/site-packages/greenlet/tests/test_gc.py new file mode 100644 index 000000000..43927d454 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/tests/test_gc.py @@ -0,0 +1,86 @@ +import gc + +import weakref + +import greenlet + + +from . import TestCase +from .leakcheck import fails_leakcheck +# These only work with greenlet gc support +# which is no longer optional. +assert greenlet.GREENLET_USE_GC + +class GCTests(TestCase): + def test_dead_circular_ref(self): + o = weakref.ref(greenlet.greenlet(greenlet.getcurrent).switch()) + gc.collect() + if o() is not None: + import sys + print("O IS NOT NONE.", sys.getrefcount(o())) + self.assertIsNone(o()) + self.assertFalse(gc.garbage, gc.garbage) + + def test_circular_greenlet(self): + class circular_greenlet(greenlet.greenlet): + pass + o = circular_greenlet() + o.self = o + o = weakref.ref(o) + gc.collect() + self.assertIsNone(o()) + self.assertFalse(gc.garbage, gc.garbage) + + def test_inactive_ref(self): + class inactive_greenlet(greenlet.greenlet): + def __init__(self): + greenlet.greenlet.__init__(self, run=self.run) + + def run(self): + pass + o = inactive_greenlet() + o = weakref.ref(o) + gc.collect() + self.assertIsNone(o()) + self.assertFalse(gc.garbage, gc.garbage) + + @fails_leakcheck + def test_finalizer_crash(self): + # This test is designed to crash when active greenlets + # are made garbage collectable, until the underlying + # problem is resolved. How does it work: + # - order of object creation is important + # - array is created first, so it is moved to unreachable first + # - we create a cycle between a greenlet and this array + # - we create an object that participates in gc, is only + # referenced by a greenlet, and would corrupt gc lists + # on destruction, the easiest is to use an object with + # a finalizer + # - because array is the first object in unreachable it is + # cleared first, which causes all references to greenlet + # to disappear and causes greenlet to be destroyed, but since + # it is still live it causes a switch during gc, which causes + # an object with finalizer to be destroyed, which causes stack + # corruption and then a crash + + class object_with_finalizer(object): + def __del__(self): + pass + array = [] + parent = greenlet.getcurrent() + def greenlet_body(): + greenlet.getcurrent().object = object_with_finalizer() + try: + parent.switch() + except greenlet.GreenletExit: + print("Got greenlet exit!") + finally: + del greenlet.getcurrent().object + g = greenlet.greenlet(greenlet_body) + g.array = array + array.append(g) + g.switch() + del array + del g + greenlet.getcurrent() + gc.collect() diff --git a/.venv/Lib/site-packages/greenlet/tests/test_generator.py b/.venv/Lib/site-packages/greenlet/tests/test_generator.py new file mode 100644 index 000000000..ca4a644b6 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/tests/test_generator.py @@ -0,0 +1,59 @@ + +from greenlet import greenlet + +from . import TestCase + +class genlet(greenlet): + parent = None + def __init__(self, *args, **kwds): + self.args = args + self.kwds = kwds + + def run(self): + fn, = self.fn + fn(*self.args, **self.kwds) + + def __iter__(self): + return self + + def __next__(self): + self.parent = greenlet.getcurrent() + result = self.switch() + if self: + return result + + raise StopIteration + + next = __next__ + + +def Yield(value): + g = greenlet.getcurrent() + while not isinstance(g, genlet): + if g is None: + raise RuntimeError('yield outside a genlet') + g = g.parent + g.parent.switch(value) + + +def generator(func): + class Generator(genlet): + fn = (func,) + return Generator + +# ____________________________________________________________ + + +class GeneratorTests(TestCase): + def test_generator(self): + seen = [] + + def g(n): + for i in range(n): + seen.append(i) + Yield(i) + g = generator(g) + for _ in range(3): + for j in g(5): + seen.append(j) + self.assertEqual(seen, 3 * [0, 0, 1, 1, 2, 2, 3, 3, 4, 4]) diff --git a/.venv/Lib/site-packages/greenlet/tests/test_generator_nested.py b/.venv/Lib/site-packages/greenlet/tests/test_generator_nested.py new file mode 100644 index 000000000..0c5d7466a --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/tests/test_generator_nested.py @@ -0,0 +1,168 @@ + +from greenlet import greenlet +from . import TestCase +from .leakcheck import fails_leakcheck + +class genlet(greenlet): + parent = None + def __init__(self, *args, **kwds): + self.args = args + self.kwds = kwds + self.child = None + + def run(self): + # Note the function is packed in a tuple + # to avoid creating a bound method for it. + fn, = self.fn + fn(*self.args, **self.kwds) + + def __iter__(self): + return self + + def set_child(self, child): + self.child = child + + def __next__(self): + if self.child: + child = self.child + while child.child: + tmp = child + child = child.child + tmp.child = None + + result = child.switch() + else: + self.parent = greenlet.getcurrent() + result = self.switch() + + if self: + return result + + raise StopIteration + + next = __next__ + +def Yield(value, level=1): + g = greenlet.getcurrent() + + while level != 0: + if not isinstance(g, genlet): + raise RuntimeError('yield outside a genlet') + if level > 1: + g.parent.set_child(g) + g = g.parent + level -= 1 + + g.switch(value) + + +def Genlet(func): + class TheGenlet(genlet): + fn = (func,) + return TheGenlet + +# ____________________________________________________________ + + +def g1(n, seen): + for i in range(n): + seen.append(i + 1) + yield i + + +def g2(n, seen): + for i in range(n): + seen.append(i + 1) + Yield(i) + +g2 = Genlet(g2) + + +def nested(i): + Yield(i) + + +def g3(n, seen): + for i in range(n): + seen.append(i + 1) + nested(i) +g3 = Genlet(g3) + + +def a(n): + if n == 0: + return + for ii in ax(n - 1): + Yield(ii) + Yield(n) +ax = Genlet(a) + + +def perms(l): + if len(l) > 1: + for e in l: + # No syntactical sugar for generator expressions + x = [Yield([e] + p) for p in perms([x for x in l if x != e])] + assert x + else: + Yield(l) +perms = Genlet(perms) + + +def gr1(n): + for ii in range(1, n): + Yield(ii) + Yield(ii * ii, 2) + +gr1 = Genlet(gr1) + + +def gr2(n, seen): + for ii in gr1(n): + seen.append(ii) + +gr2 = Genlet(gr2) + + +class NestedGeneratorTests(TestCase): + def test_layered_genlets(self): + seen = [] + for ii in gr2(5, seen): + seen.append(ii) + self.assertEqual(seen, [1, 1, 2, 4, 3, 9, 4, 16]) + + @fails_leakcheck + def test_permutations(self): + gen_perms = perms(list(range(4))) + permutations = list(gen_perms) + self.assertEqual(len(permutations), 4 * 3 * 2 * 1) + self.assertIn([0, 1, 2, 3], permutations) + self.assertIn([3, 2, 1, 0], permutations) + res = [] + for ii in zip(perms(list(range(4))), perms(list(range(3)))): + res.append(ii) + self.assertEqual( + res, + [([0, 1, 2, 3], [0, 1, 2]), ([0, 1, 3, 2], [0, 2, 1]), + ([0, 2, 1, 3], [1, 0, 2]), ([0, 2, 3, 1], [1, 2, 0]), + ([0, 3, 1, 2], [2, 0, 1]), ([0, 3, 2, 1], [2, 1, 0])]) + # XXX Test to make sure we are working as a generator expression + + def test_genlet_simple(self): + for g in [g1, g2, g3]: + seen = [] + for _ in range(3): + for j in g(5, seen): + seen.append(j) + self.assertEqual(seen, 3 * [1, 0, 2, 1, 3, 2, 4, 3, 5, 4]) + + def test_genlet_bad(self): + try: + Yield(10) + except RuntimeError: + pass + + def test_nested_genlets(self): + seen = [] + for ii in ax(5): + seen.append(ii) diff --git a/.venv/Lib/site-packages/greenlet/tests/test_greenlet.py b/.venv/Lib/site-packages/greenlet/tests/test_greenlet.py new file mode 100644 index 000000000..3185b39bd --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/tests/test_greenlet.py @@ -0,0 +1,1126 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import gc +import sys +import time +import threading + +from abc import ABCMeta, abstractmethod + +from greenlet import greenlet +from . import TestCase +from .leakcheck import fails_leakcheck + + +# We manually manage locks in many tests +# pylint:disable=consider-using-with +# pylint:disable=too-many-public-methods + +class SomeError(Exception): + pass + + +def fmain(seen): + try: + greenlet.getcurrent().parent.switch() + except: + seen.append(sys.exc_info()[0]) + raise + raise SomeError + + +def send_exception(g, exc): + # note: send_exception(g, exc) can be now done with g.throw(exc). + # the purpose of this test is to explicitly check the propagation rules. + def crasher(exc): + raise exc + g1 = greenlet(crasher, parent=g) + g1.switch(exc) + + +class TestGreenlet(TestCase): + + def _do_simple_test(self): + lst = [] + + def f(): + lst.append(1) + greenlet.getcurrent().parent.switch() + lst.append(3) + g = greenlet(f) + lst.append(0) + g.switch() + lst.append(2) + g.switch() + lst.append(4) + self.assertEqual(lst, list(range(5))) + + def test_simple(self): + self._do_simple_test() + + def test_switch_no_run_raises_AttributeError(self): + g = greenlet() + with self.assertRaises(AttributeError) as exc: + g.switch() + + self.assertIn("run", str(exc.exception)) + + def test_throw_no_run_raises_AttributeError(self): + g = greenlet() + with self.assertRaises(AttributeError) as exc: + g.throw(SomeError) + + self.assertIn("run", str(exc.exception)) + + def test_parent_equals_None(self): + g = greenlet(parent=None) + self.assertIsNotNone(g) + self.assertIs(g.parent, greenlet.getcurrent()) + + def test_run_equals_None(self): + g = greenlet(run=None) + self.assertIsNotNone(g) + self.assertIsNone(g.run) + + def test_two_children(self): + lst = [] + + def f(): + lst.append(1) + greenlet.getcurrent().parent.switch() + lst.extend([1, 1]) + g = greenlet(f) + h = greenlet(f) + g.switch() + self.assertEqual(len(lst), 1) + h.switch() + self.assertEqual(len(lst), 2) + h.switch() + self.assertEqual(len(lst), 4) + self.assertEqual(h.dead, True) + g.switch() + self.assertEqual(len(lst), 6) + self.assertEqual(g.dead, True) + + def test_two_recursive_children(self): + lst = [] + + def f(): + lst.append('b') + greenlet.getcurrent().parent.switch() + + def g(): + lst.append('a') + g = greenlet(f) + g.switch() + lst.append('c') + + g = greenlet(g) + self.assertEqual(sys.getrefcount(g), 2) + g.switch() + self.assertEqual(lst, ['a', 'b', 'c']) + # Just the one in this frame, plus the one on the stack we pass to the function + self.assertEqual(sys.getrefcount(g), 2) + + def test_threads(self): + success = [] + + def f(): + self._do_simple_test() + success.append(True) + ths = [threading.Thread(target=f) for i in range(10)] + for th in ths: + th.start() + for th in ths: + th.join(10) + self.assertEqual(len(success), len(ths)) + + def test_exception(self): + seen = [] + g1 = greenlet(fmain) + g2 = greenlet(fmain) + g1.switch(seen) + g2.switch(seen) + g2.parent = g1 + + self.assertEqual(seen, []) + #with self.assertRaises(SomeError): + # p("***Switching back") + # g2.switch() + # Creating this as a bound method can reveal bugs that + # are hidden on newer versions of Python that avoid creating + # bound methods for direct expressions; IOW, don't use the `with` + # form! + self.assertRaises(SomeError, g2.switch) + self.assertEqual(seen, [SomeError]) + + value = g2.switch() + self.assertEqual(value, ()) + self.assertEqual(seen, [SomeError]) + + value = g2.switch(25) + self.assertEqual(value, 25) + self.assertEqual(seen, [SomeError]) + + + def test_send_exception(self): + seen = [] + g1 = greenlet(fmain) + g1.switch(seen) + self.assertRaises(KeyError, send_exception, g1, KeyError) + self.assertEqual(seen, [KeyError]) + + def test_dealloc(self): + seen = [] + g1 = greenlet(fmain) + g2 = greenlet(fmain) + g1.switch(seen) + g2.switch(seen) + self.assertEqual(seen, []) + del g1 + gc.collect() + self.assertEqual(seen, [greenlet.GreenletExit]) + del g2 + gc.collect() + self.assertEqual(seen, [greenlet.GreenletExit, greenlet.GreenletExit]) + + def test_dealloc_catches_GreenletExit_throws_other(self): + def run(): + try: + greenlet.getcurrent().parent.switch() + except greenlet.GreenletExit: + raise SomeError + + g = greenlet(run) + g.switch() + # Destroying the only reference to the greenlet causes it + # to get GreenletExit; when it in turn raises, even though we're the parent + # we don't get the exception, it just gets printed. + # When we run on 3.8 only, we can use sys.unraisablehook + oldstderr = sys.stderr + try: + from cStringIO import StringIO + except ImportError: + from io import StringIO + stderr = sys.stderr = StringIO() + try: + del g + finally: + sys.stderr = oldstderr + + v = stderr.getvalue() + self.assertIn("Exception", v) + self.assertIn('ignored', v) + self.assertIn("SomeError", v) + + + def test_dealloc_other_thread(self): + seen = [] + someref = [] + + bg_glet_created_running_and_no_longer_ref_in_bg = threading.Event() + fg_ref_released = threading.Event() + bg_should_be_clear = threading.Event() + ok_to_exit_bg_thread = threading.Event() + + def f(): + g1 = greenlet(fmain) + g1.switch(seen) + someref.append(g1) + del g1 + gc.collect() + + bg_glet_created_running_and_no_longer_ref_in_bg.set() + fg_ref_released.wait(3) + + greenlet() # trigger release + bg_should_be_clear.set() + ok_to_exit_bg_thread.wait(3) + greenlet() # One more time + + t = threading.Thread(target=f) + t.start() + bg_glet_created_running_and_no_longer_ref_in_bg.wait(10) + + self.assertEqual(seen, []) + self.assertEqual(len(someref), 1) + del someref[:] + gc.collect() + # g1 is not released immediately because it's from another thread + self.assertEqual(seen, []) + fg_ref_released.set() + bg_should_be_clear.wait(3) + try: + self.assertEqual(seen, [greenlet.GreenletExit]) + finally: + ok_to_exit_bg_thread.set() + t.join(10) + del seen[:] + del someref[:] + + def test_frame(self): + def f1(): + f = sys._getframe(0) # pylint:disable=protected-access + self.assertEqual(f.f_back, None) + greenlet.getcurrent().parent.switch(f) + return "meaning of life" + g = greenlet(f1) + frame = g.switch() + self.assertTrue(frame is g.gr_frame) + self.assertTrue(g) + + from_g = g.switch() + self.assertFalse(g) + self.assertEqual(from_g, 'meaning of life') + self.assertEqual(g.gr_frame, None) + + def test_thread_bug(self): + def runner(x): + g = greenlet(lambda: time.sleep(x)) + g.switch() + t1 = threading.Thread(target=runner, args=(0.2,)) + t2 = threading.Thread(target=runner, args=(0.3,)) + t1.start() + t2.start() + t1.join(10) + t2.join(10) + + def test_switch_kwargs(self): + def run(a, b): + self.assertEqual(a, 4) + self.assertEqual(b, 2) + return 42 + x = greenlet(run).switch(a=4, b=2) + self.assertEqual(x, 42) + + def test_switch_kwargs_to_parent(self): + def run(x): + greenlet.getcurrent().parent.switch(x=x) + greenlet.getcurrent().parent.switch(2, x=3) + return x, x ** 2 + g = greenlet(run) + self.assertEqual({'x': 3}, g.switch(3)) + self.assertEqual(((2,), {'x': 3}), g.switch()) + self.assertEqual((3, 9), g.switch()) + + def test_switch_to_another_thread(self): + data = {} + created_event = threading.Event() + done_event = threading.Event() + + def run(): + data['g'] = greenlet(lambda: None) + created_event.set() + done_event.wait(10) + thread = threading.Thread(target=run) + thread.start() + created_event.wait(10) + with self.assertRaises(greenlet.error): + data['g'].switch() + done_event.set() + thread.join(10) + # XXX: Should handle this automatically + data.clear() + + def test_exc_state(self): + def f(): + try: + raise ValueError('fun') + except: # pylint:disable=bare-except + exc_info = sys.exc_info() + greenlet(h).switch() + self.assertEqual(exc_info, sys.exc_info()) + + def h(): + self.assertEqual(sys.exc_info(), (None, None, None)) + + greenlet(f).switch() + + def test_instance_dict(self): + def f(): + greenlet.getcurrent().test = 42 + def deldict(g): + del g.__dict__ + def setdict(g, value): + g.__dict__ = value + g = greenlet(f) + self.assertEqual(g.__dict__, {}) + g.switch() + self.assertEqual(g.test, 42) + self.assertEqual(g.__dict__, {'test': 42}) + g.__dict__ = g.__dict__ + self.assertEqual(g.__dict__, {'test': 42}) + self.assertRaises(TypeError, deldict, g) + self.assertRaises(TypeError, setdict, g, 42) + + def test_running_greenlet_has_no_run(self): + has_run = [] + def func(): + has_run.append( + hasattr(greenlet.getcurrent(), 'run') + ) + + g = greenlet(func) + g.switch() + self.assertEqual(has_run, [False]) + + def test_deepcopy(self): + import copy + self.assertRaises(TypeError, copy.copy, greenlet()) + self.assertRaises(TypeError, copy.deepcopy, greenlet()) + + def test_parent_restored_on_kill(self): + hub = greenlet(lambda: None) + main = greenlet.getcurrent() + result = [] + def worker(): + try: + # Wait to be killed by going back to the test. + main.switch() + except greenlet.GreenletExit: + # Resurrect and switch to parent + result.append(greenlet.getcurrent().parent) + result.append(greenlet.getcurrent()) + hub.switch() + g = greenlet(worker, parent=hub) + g.switch() + # delete the only reference, thereby raising GreenletExit + del g + self.assertTrue(result) + self.assertIs(result[0], main) + self.assertIs(result[1].parent, hub) + # Delete them, thereby breaking the cycle between the greenlet + # and the frame, which otherwise would never be collectable + # XXX: We should be able to automatically fix this. + del result[:] + hub = None + main = None + + def test_parent_return_failure(self): + # No run causes AttributeError on switch + g1 = greenlet() + # Greenlet that implicitly switches to parent + g2 = greenlet(lambda: None, parent=g1) + # AttributeError should propagate to us, no fatal errors + with self.assertRaises(AttributeError): + g2.switch() + + def test_throw_exception_not_lost(self): + class mygreenlet(greenlet): + def __getattribute__(self, name): + try: + raise Exception() + except: # pylint:disable=bare-except + pass + return greenlet.__getattribute__(self, name) + g = mygreenlet(lambda: None) + self.assertRaises(SomeError, g.throw, SomeError()) + + @fails_leakcheck + def _do_test_throw_to_dead_thread_doesnt_crash(self, wait_for_cleanup=False): + result = [] + def worker(): + greenlet.getcurrent().parent.switch() + + def creator(): + g = greenlet(worker) + g.switch() + result.append(g) + if wait_for_cleanup: + # Let this greenlet eventually be cleaned up. + g.switch() + greenlet.getcurrent() + t = threading.Thread(target=creator) + t.start() + t.join(10) + del t + # But, depending on the operating system, the thread + # deallocator may not actually have run yet! So we can't be + # sure about the error message unless we wait. + if wait_for_cleanup: + self.wait_for_pending_cleanups() + with self.assertRaises(greenlet.error) as exc: + result[0].throw(SomeError) + + if not wait_for_cleanup: + self.assertIn( + str(exc.exception), [ + "cannot switch to a different thread (which happens to have exited)", + "cannot switch to a different thread" + ] + ) + else: + self.assertEqual( + str(exc.exception), + "cannot switch to a different thread (which happens to have exited)", + ) + + if hasattr(result[0].gr_frame, 'clear'): + # The frame is actually executing (it thinks), we can't clear it. + with self.assertRaises(RuntimeError): + result[0].gr_frame.clear() + # Unfortunately, this doesn't actually clear the references, they're in the + # fast local array. + if not wait_for_cleanup: + result[0].gr_frame.f_locals.clear() + else: + self.assertIsNone(result[0].gr_frame) + + del creator + worker = None + del result[:] + # XXX: we ought to be able to automatically fix this. + # See issue 252 + self.expect_greenlet_leak = True # direct us not to wait for it to go away + + @fails_leakcheck + def test_throw_to_dead_thread_doesnt_crash(self): + self._do_test_throw_to_dead_thread_doesnt_crash() + + def test_throw_to_dead_thread_doesnt_crash_wait(self): + self._do_test_throw_to_dead_thread_doesnt_crash(True) + + @fails_leakcheck + def test_recursive_startup(self): + class convoluted(greenlet): + def __init__(self): + greenlet.__init__(self) + self.count = 0 + def __getattribute__(self, name): + if name == 'run' and self.count == 0: + self.count = 1 + self.switch(43) + return greenlet.__getattribute__(self, name) + def run(self, value): + while True: + self.parent.switch(value) + g = convoluted() + self.assertEqual(g.switch(42), 43) + # Exits the running greenlet, otherwise it leaks + # XXX: We should be able to automatically fix this + #g.throw(greenlet.GreenletExit) + #del g + self.expect_greenlet_leak = True + + def test_threaded_updatecurrent(self): + # released when main thread should execute + lock1 = threading.Lock() + lock1.acquire() + # released when another thread should execute + lock2 = threading.Lock() + lock2.acquire() + class finalized(object): + def __del__(self): + # happens while in green_updatecurrent() in main greenlet + # should be very careful not to accidentally call it again + # at the same time we must make sure another thread executes + lock2.release() + lock1.acquire() + # now ts_current belongs to another thread + def deallocator(): + greenlet.getcurrent().parent.switch() + def fthread(): + lock2.acquire() + greenlet.getcurrent() + del g[0] + lock1.release() + lock2.acquire() + greenlet.getcurrent() + lock1.release() + main = greenlet.getcurrent() + g = [greenlet(deallocator)] + g[0].bomb = finalized() + g[0].switch() + t = threading.Thread(target=fthread) + t.start() + # let another thread grab ts_current and deallocate g[0] + lock2.release() + lock1.acquire() + # this is the corner stone + # getcurrent() will notice that ts_current belongs to another thread + # and start the update process, which would notice that g[0] should + # be deallocated, and that will execute an object's finalizer. Now, + # that object will let another thread run so it can grab ts_current + # again, which would likely crash the interpreter if there's no + # check for this case at the end of green_updatecurrent(). This test + # passes if getcurrent() returns correct result, but it's likely + # to randomly crash if it's not anyway. + self.assertEqual(greenlet.getcurrent(), main) + # wait for another thread to complete, just in case + t.join(10) + + def test_dealloc_switch_args_not_lost(self): + seen = [] + def worker(): + # wait for the value + value = greenlet.getcurrent().parent.switch() + # delete all references to ourself + del worker[0] + initiator.parent = greenlet.getcurrent().parent + # switch to main with the value, but because + # ts_current is the last reference to us we + # return here immediately, where we resurrect ourself. + try: + greenlet.getcurrent().parent.switch(value) + finally: + seen.append(greenlet.getcurrent()) + def initiator(): + return 42 # implicitly falls thru to parent + + worker = [greenlet(worker)] + + worker[0].switch() # prime worker + initiator = greenlet(initiator, worker[0]) + value = initiator.switch() + self.assertTrue(seen) + self.assertEqual(value, 42) + + def test_tuple_subclass(self): + # XXX: This is failing on Python 2 with a SystemError: error return without exception set + + # The point of this test is to see what happens when a custom + # tuple subclass is used as an object passed directly to the C + # function ``green_switch``; part of ``green_switch`` checks + # the ``len()`` of the ``args`` tuple, and that can call back + # into Python. Here, when it calls back into Python, we + # recursively enter ``green_switch`` again. + + # This test is really only relevant on Python 2. The builtin + # `apply` function directly passes the given args tuple object + # to the underlying function, whereas the Python 3 version + # unpacks and repacks into an actual tuple. This could still + # happen using the C API on Python 3 though. + if sys.version_info[0] > 2: + # There's no apply in Python 3.x + def _apply(func, a, k): + func(*a, **k) + else: + _apply = apply # pylint:disable=undefined-variable + + class mytuple(tuple): + def __len__(self): + greenlet.getcurrent().switch() + return tuple.__len__(self) + args = mytuple() + kwargs = dict(a=42) + def switchapply(): + _apply(greenlet.getcurrent().parent.switch, args, kwargs) + g = greenlet(switchapply) + self.assertEqual(g.switch(), kwargs) + + def test_abstract_subclasses(self): + AbstractSubclass = ABCMeta( + 'AbstractSubclass', + (greenlet,), + {'run': abstractmethod(lambda self: None)}) + + class BadSubclass(AbstractSubclass): + pass + + class GoodSubclass(AbstractSubclass): + def run(self): + pass + + GoodSubclass() # should not raise + self.assertRaises(TypeError, BadSubclass) + + def test_implicit_parent_with_threads(self): + if not gc.isenabled(): + return # cannot test with disabled gc + N = gc.get_threshold()[0] + if N < 50: + return # cannot test with such a small N + def attempt(): + lock1 = threading.Lock() + lock1.acquire() + lock2 = threading.Lock() + lock2.acquire() + recycled = [False] + def another_thread(): + lock1.acquire() # wait for gc + greenlet.getcurrent() # update ts_current + lock2.release() # release gc + t = threading.Thread(target=another_thread) + t.start() + class gc_callback(object): + def __del__(self): + lock1.release() + lock2.acquire() + recycled[0] = True + class garbage(object): + def __init__(self): + self.cycle = self + self.callback = gc_callback() + l = [] + x = range(N*2) + current = greenlet.getcurrent() + g = garbage() + for _ in x: + g = None # lose reference to garbage + if recycled[0]: + # gc callback called prematurely + t.join(10) + return False + last = greenlet() + if recycled[0]: + break # yes! gc called in green_new + l.append(last) # increase allocation counter + else: + # gc callback not called when expected + gc.collect() + if recycled[0]: + t.join(10) + return False + self.assertEqual(last.parent, current) + for g in l: + self.assertEqual(g.parent, current) + return True + for _ in range(5): + if attempt(): + break + + def test_issue_245_reference_counting_subclass_no_threads(self): + # https://github.com/python-greenlet/greenlet/issues/245 + # Before the fix, this crashed pretty reliably on + # Python 3.10, at least on macOS; but much less reliably on other + # interpreters (memory layout must have changed). + # The threaded test crashed more reliably on more interpreters. + from greenlet import getcurrent + from greenlet import GreenletExit + + class Greenlet(greenlet): + pass + + initial_refs = sys.getrefcount(Greenlet) + # This has to be an instance variable because + # Python 2 raises a SyntaxError if we delete a local + # variable referenced in an inner scope. + self.glets = [] # pylint:disable=attribute-defined-outside-init + + def greenlet_main(): + try: + getcurrent().parent.switch() + except GreenletExit: + self.glets.append(getcurrent()) + + # Before the + for _ in range(10): + Greenlet(greenlet_main).switch() + + del self.glets + self.assertEqual(sys.getrefcount(Greenlet), initial_refs) + + def test_issue_245_reference_counting_subclass_threads(self): + # https://github.com/python-greenlet/greenlet/issues/245 + from threading import Thread + from threading import Event + + from greenlet import getcurrent + + class MyGreenlet(greenlet): + pass + + glets = [] + ref_cleared = Event() + + def greenlet_main(): + getcurrent().parent.switch() + + def thread_main(greenlet_running_event): + mine = MyGreenlet(greenlet_main) + glets.append(mine) + # The greenlets being deleted must be active + mine.switch() + # Don't keep any reference to it in this thread + del mine + # Let main know we published our greenlet. + greenlet_running_event.set() + # Wait for main to let us know the references are + # gone and the greenlet objects no longer reachable + ref_cleared.wait(10) + # The creating thread must call getcurrent() (or a few other + # greenlet APIs) because that's when the thread-local list of dead + # greenlets gets cleared. + getcurrent() + + # We start with 3 references to the subclass: + # - This module + # - Its __mro__ + # - The __subclassess__ attribute of greenlet + # - (If we call gc.get_referents(), we find four entries, including + # some other tuple ``(greenlet)`` that I'm not sure about but must be part + # of the machinery.) + # + # On Python 3.10 it's often enough to just run 3 threads; on Python 2.7, + # more threads are needed, and the results are still + # non-deterministic. Presumably the memory layouts are different + initial_refs = sys.getrefcount(MyGreenlet) + thread_ready_events = [] + for _ in range( + initial_refs + 45 + ): + event = Event() + thread = Thread(target=thread_main, args=(event,)) + thread_ready_events.append(event) + thread.start() + + + for done_event in thread_ready_events: + done_event.wait(10) + + + del glets[:] + ref_cleared.set() + # Let any other thread run; it will crash the interpreter + # if not fixed (or silently corrupt memory and we possibly crash + # later). + self.wait_for_pending_cleanups() + self.assertEqual(sys.getrefcount(MyGreenlet), initial_refs) + + def test_falling_off_end_switches_to_unstarted_parent_raises_error(self): + def no_args(): + return 13 + + parent_never_started = greenlet(no_args) + + def leaf(): + return 42 + + child = greenlet(leaf, parent_never_started) + + # Because the run function takes to arguments + with self.assertRaises(TypeError): + child.switch() + + def test_falling_off_end_switches_to_unstarted_parent_works(self): + def one_arg(x): + return (x, 24) + + parent_never_started = greenlet(one_arg) + + def leaf(): + return 42 + + child = greenlet(leaf, parent_never_started) + + result = child.switch() + self.assertEqual(result, (42, 24)) + + def test_switch_to_dead_greenlet_with_unstarted_perverse_parent(self): + class Parent(greenlet): + def __getattribute__(self, name): + if name == 'run': + raise SomeError + + + parent_never_started = Parent() + seen = [] + child = greenlet(lambda: seen.append(42), parent_never_started) + # Because we automatically start the parent when the child is + # finished + with self.assertRaises(SomeError): + child.switch() + + self.assertEqual(seen, [42]) + + with self.assertRaises(SomeError): + child.switch() + self.assertEqual(seen, [42]) + + def test_switch_to_dead_greenlet_reparent(self): + seen = [] + parent_never_started = greenlet(lambda: seen.append(24)) + child = greenlet(lambda: seen.append(42)) + + child.switch() + self.assertEqual(seen, [42]) + + child.parent = parent_never_started + # This actually is the same as switching to the parent. + result = child.switch() + self.assertIsNone(result) + self.assertEqual(seen, [42, 24]) + + +class TestGreenletSetParentErrors(TestCase): + def test_threaded_reparent(self): + data = {} + created_event = threading.Event() + done_event = threading.Event() + + def run(): + data['g'] = greenlet(lambda: None) + created_event.set() + done_event.wait(10) + + def blank(): + greenlet.getcurrent().parent.switch() + + thread = threading.Thread(target=run) + thread.start() + created_event.wait(10) + g = greenlet(blank) + g.switch() + with self.assertRaises(ValueError) as exc: + g.parent = data['g'] + done_event.set() + thread.join(10) + + self.assertEqual(str(exc.exception), "parent cannot be on a different thread") + + def test_unexpected_reparenting(self): + another = [] + def worker(): + g = greenlet(lambda: None) + another.append(g) + g.switch() + t = threading.Thread(target=worker) + t.start() + t.join(10) + # The first time we switch (running g_initialstub(), which is + # when we look up the run attribute) we attempt to change the + # parent to one from another thread (which also happens to be + # dead). ``g_initialstub()`` should detect this and raise a + # greenlet error. + # + # EXCEPT: With the fix for #252, this is actually detected + # sooner, when setting the parent itself. Prior to that fix, + # the main greenlet from the background thread kept a valid + # value for ``run_info``, and appeared to be a valid parent + # until we actually started the greenlet. But now that it's + # cleared, this test is catching whether ``green_setparent`` + # can detect the dead thread. + # + # Further refactoring once again changes this back to a greenlet.error + # + # We need to wait for the cleanup to happen, but we're + # deliberately leaking a main greenlet here. + self.wait_for_pending_cleanups(initial_main_greenlets=self.main_greenlets_before_test + 1) + + class convoluted(greenlet): + def __getattribute__(self, name): + if name == 'run': + self.parent = another[0] # pylint:disable=attribute-defined-outside-init + return greenlet.__getattribute__(self, name) + g = convoluted(lambda: None) + with self.assertRaises(greenlet.error) as exc: + g.switch() + self.assertEqual(str(exc.exception), + "cannot switch to a different thread (which happens to have exited)") + del another[:] + + def test_unexpected_reparenting_thread_running(self): + # Like ``test_unexpected_reparenting``, except the background thread is + # actually still alive. + another = [] + switched_to_greenlet = threading.Event() + keep_main_alive = threading.Event() + def worker(): + g = greenlet(lambda: None) + another.append(g) + g.switch() + switched_to_greenlet.set() + keep_main_alive.wait(10) + class convoluted(greenlet): + def __getattribute__(self, name): + if name == 'run': + self.parent = another[0] # pylint:disable=attribute-defined-outside-init + return greenlet.__getattribute__(self, name) + + t = threading.Thread(target=worker) + t.start() + + switched_to_greenlet.wait(10) + try: + g = convoluted(lambda: None) + + with self.assertRaises(greenlet.error) as exc: + g.switch() + self.assertEqual(str(exc.exception), "cannot switch to a different thread") + finally: + keep_main_alive.set() + t.join(10) + # XXX: Should handle this automatically. + del another[:] + + def test_cannot_delete_parent(self): + worker = greenlet(lambda: None) + self.assertIs(worker.parent, greenlet.getcurrent()) + + with self.assertRaises(AttributeError) as exc: + del worker.parent + self.assertEqual(str(exc.exception), "can't delete attribute") + + def test_cannot_delete_parent_of_main(self): + with self.assertRaises(AttributeError) as exc: + del greenlet.getcurrent().parent + self.assertEqual(str(exc.exception), "can't delete attribute") + + + def test_main_greenlet_parent_is_none(self): + # assuming we're in a main greenlet here. + self.assertIsNone(greenlet.getcurrent().parent) + + def test_set_parent_wrong_types(self): + def bg(): + # Go back to main. + greenlet.getcurrent().parent.switch() + + def check(glet): + for p in None, 1, self, "42": + with self.assertRaises(TypeError) as exc: + glet.parent = p + + self.assertEqual( + str(exc.exception), + "GreenletChecker: Expected any type of greenlet, not " + type(p).__name__) + + # First, not running + g = greenlet(bg) + self.assertFalse(g) + check(g) + + # Then when running. + g.switch() + self.assertTrue(g) + check(g) + + # Let it finish + g.switch() + + + def test_trivial_cycle(self): + glet = greenlet(lambda: None) + with self.assertRaises(ValueError) as exc: + glet.parent = glet + self.assertEqual(str(exc.exception), "cyclic parent chain") + + def test_trivial_cycle_main(self): + # This used to produce a ValueError, but we catch it earlier than that now. + with self.assertRaises(AttributeError) as exc: + greenlet.getcurrent().parent = greenlet.getcurrent() + self.assertEqual(str(exc.exception), "cannot set the parent of a main greenlet") + + def test_deeper_cycle(self): + g1 = greenlet(lambda: None) + g2 = greenlet(lambda: None) + g3 = greenlet(lambda: None) + + g1.parent = g2 + g2.parent = g3 + with self.assertRaises(ValueError) as exc: + g3.parent = g1 + self.assertEqual(str(exc.exception), "cyclic parent chain") + + +class TestRepr(TestCase): + + def assertEndsWith(self, got, suffix): + self.assertTrue(got.endswith(suffix), (got, suffix)) + + def test_main_while_running(self): + r = repr(greenlet.getcurrent()) + self.assertEndsWith(r, " current active started main>") + + def test_main_in_background(self): + main = greenlet.getcurrent() + def run(): + return repr(main) + + g = greenlet(run) + r = g.switch() + self.assertEndsWith(r, ' suspended active started main>') + + def test_initial(self): + r = repr(greenlet()) + self.assertEndsWith(r, ' pending>') + + def test_main_from_other_thread(self): + main = greenlet.getcurrent() + + class T(threading.Thread): + original_main = thread_main = None + main_glet = None + def run(self): + self.original_main = repr(main) + self.main_glet = greenlet.getcurrent() + self.thread_main = repr(self.main_glet) + + t = T() + t.start() + t.join(10) + + self.assertEndsWith(t.original_main, ' suspended active started main>') + self.assertEndsWith(t.thread_main, ' current active started main>') + # give the machinery time to notice the death of the thread, + # and clean it up. Note that we don't use + # ``expect_greenlet_leak`` or wait_for_pending_cleanups, + # because at this point we know we have an extra greenlet + # still reachable. + for _ in range(3): + time.sleep(0.001) + + # In the past, main greenlets, even from dead threads, never + # really appear dead. We have fixed that, and we also report + # that the thread is dead in the repr. (Do this multiple times + # to make sure that we don't self-modify and forget our state + # in the C++ code). + for _ in range(3): + self.assertTrue(t.main_glet.dead) + r = repr(t.main_glet) + self.assertEndsWith(r, ' (thread exited) dead>') + + def test_dead(self): + g = greenlet(lambda: None) + g.switch() + self.assertEndsWith(repr(g), ' dead>') + self.assertNotIn('suspended', repr(g)) + self.assertNotIn('started', repr(g)) + self.assertNotIn('active', repr(g)) + + def test_formatting_produces_native_str(self): + # https://github.com/python-greenlet/greenlet/issues/218 + # %s formatting on Python 2 was producing unicode, not str. + + g_dead = greenlet(lambda: None) + g_not_started = greenlet(lambda: None) + g_cur = greenlet.getcurrent() + + for g in g_dead, g_not_started, g_cur: + + self.assertIsInstance( + '%s' % (g,), + str + ) + self.assertIsInstance( + '%r' % (g,), + str, + ) + + +class TestMainGreenlet(TestCase): + # Tests some implementation details, and relies on some + # implementation details. + + def _check_current_is_main(self): + # implementation detail + assert 'main' in repr(greenlet.getcurrent()) + + t = type(greenlet.getcurrent()) + assert 'main' not in repr(t) + return t + + def test_main_greenlet_type_can_be_subclassed(self): + main_type = self._check_current_is_main() + subclass = type('subclass', (main_type,), {}) + self.assertIsNotNone(subclass) + + def test_main_greenlet_is_greenlet(self): + self._check_current_is_main() + self.assertIsInstance(greenlet.getcurrent(), greenlet) + +if __name__ == '__main__': + import unittest + unittest.main() diff --git a/.venv/Lib/site-packages/greenlet/tests/test_greenlet_trash.py b/.venv/Lib/site-packages/greenlet/tests/test_greenlet_trash.py new file mode 100644 index 000000000..6dface3bf --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/tests/test_greenlet_trash.py @@ -0,0 +1,185 @@ +# -*- coding: utf-8 -*- +""" +Tests for greenlets interacting with the CPython trash can API. + +The CPython trash can API is not designed to be re-entered from a +single thread. But this can happen using greenlets, if something +during the object deallocation process switches greenlets, and this second +greenlet then causes the trash can to get entered again. Here, we do this +very explicitly, but in other cases (like gevent) it could be arbitrarily more +complicated: for example, a weakref callback might try to acquire a lock that's +already held by another greenlet; that would allow a greenlet switch to occur. + +See https://github.com/gevent/gevent/issues/1909 + +This test is fragile and relies on details of the CPython +implementation (like most of the rest of this package): + + - We enter the trashcan and deferred deallocation after + ``_PyTrash_UNWIND_LEVEL`` calls. This constant, defined in + CPython's object.c, is generally 50. That's basically how many objects are required to + get us into the deferred deallocation situation. + + - The test fails by hitting an ``assert()`` in object.c; if the + build didn't enable assert, then we don't catch this. + + - If the test fails in that way, the interpreter crashes. +""" +from __future__ import print_function, absolute_import, division + +import sys +import unittest + + + +class TestTrashCanReEnter(unittest.TestCase): + + @unittest.skipUnless( + sys.version_info[0] > 2, + "Python 2 tracks this slightly differently, so our test doesn't catch a problem there. " + ) + def test_it(self): + # Try several times to trigger it, because it isn't 100% + # reliable. + for _ in range(10): + self.check_it() + + def check_it(self): # pylint:disable=too-many-statements + import greenlet + from greenlet._greenlet import get_tstate_trash_delete_nesting # pylint:disable=no-name-in-module + + main = greenlet.getcurrent() + + assert get_tstate_trash_delete_nesting() == 0 + + # We expect to be in deferred deallocation after this many + # deallocations have occurred. TODO: I wish we had a better way to do + # this --- that was before get_tstate_trash_delete_nesting; perhaps + # we can use that API to do better? + TRASH_UNWIND_LEVEL = 50 + # How many objects to put in a container; it's the container that + # queues objects for deferred deallocation. + OBJECTS_PER_CONTAINER = 500 + + class Dealloc: # define the class here because we alter class variables each time we run. + """ + An object with a ``__del__`` method. When it starts getting deallocated + from a deferred trash can run, it switches greenlets, allocates more objects + which then also go in the trash can. If we don't save state appropriately, + nesting gets out of order and we can crash the interpreter. + """ + + #: Has our deallocation actually run and switched greenlets? + #: When it does, this will be set to the current greenlet. This should + #: be happening in the main greenlet, so we check that down below. + SPAWNED = False + + #: Has the background greenlet run? + BG_RAN = False + + BG_GLET = None + + #: How many of these things have ever been allocated. + CREATED = 0 + + #: How many of these things have ever been deallocated. + DESTROYED = 0 + + #: How many were destroyed not in the main greenlet. There should always + #: be some. + #: If the test is broken or things change in the trashcan implementation, + #: this may not be correct. + DESTROYED_BG = 0 + + def __init__(self, sequence_number): + """ + :param sequence_number: The ordinal of this object during + one particular creation run. This is used to detect (guess, really) + when we have entered the trash can's deferred deallocation. + """ + self.i = sequence_number + Dealloc.CREATED += 1 + + def __del__(self): + if self.i == TRASH_UNWIND_LEVEL and not self.SPAWNED: + Dealloc.SPAWNED = greenlet.getcurrent() + other = Dealloc.BG_GLET = greenlet.greenlet(background_greenlet) + x = other.switch() + assert x == 42 + # It's important that we don't switch back to the greenlet, + # we leave it hanging there in an incomplete state. But we don't let it + # get collected, either. If we complete it now, while we're still + # in the scope of the initial trash can, things work out and we + # don't see the problem. We need this greenlet to complete + # at some point in the future, after we've exited this trash can invocation. + del other + elif self.i == 40 and greenlet.getcurrent() is not main: + Dealloc.BG_RAN = True + try: + main.switch(42) + except greenlet.GreenletExit as ex: + # We expect this; all references to us go away + # while we're still running, and we need to finish deleting + # ourself. + Dealloc.BG_RAN = type(ex) + del ex + + # Record the fact that we're dead last of all. This ensures that + # we actually get returned too. + Dealloc.DESTROYED += 1 + if greenlet.getcurrent() is not main: + Dealloc.DESTROYED_BG += 1 + + + def background_greenlet(): + # We direct through a second function, instead of + # directly calling ``make_some()``, so that we have complete + # control over when these objects are destroyed: we need them + # to be destroyed in the context of the background greenlet + t = make_some() + del t # Triggere deletion. + + def make_some(): + t = () + i = OBJECTS_PER_CONTAINER + while i: + # Nest the tuples; it's the recursion that gets us + # into trash. + t = (Dealloc(i), t) + i -= 1 + return t + + + some = make_some() + self.assertEqual(Dealloc.CREATED, OBJECTS_PER_CONTAINER) + self.assertEqual(Dealloc.DESTROYED, 0) + + # If we're going to crash, it should be on the following line. + # We only crash if ``assert()`` is enabled, of course. + del some + + # For non-debug builds of CPython, we won't crash. The best we can do is check + # the nesting level explicitly. + self.assertEqual(0, get_tstate_trash_delete_nesting()) + + # Discard this, raising GreenletExit into where it is waiting. + Dealloc.BG_GLET = None + # The same nesting level maintains. + self.assertEqual(0, get_tstate_trash_delete_nesting()) + + # We definitely cleaned some up in the background + self.assertGreater(Dealloc.DESTROYED_BG, 0) + + # Make sure all the cleanups happened. + self.assertIs(Dealloc.SPAWNED, main) + self.assertTrue(Dealloc.BG_RAN) + self.assertEqual(Dealloc.BG_RAN, greenlet.GreenletExit) + self.assertEqual(Dealloc.CREATED, Dealloc.DESTROYED ) + self.assertEqual(Dealloc.CREATED, OBJECTS_PER_CONTAINER * 2) + + import gc + gc.collect() + + +if __name__ == '__main__': + unittest.main() diff --git a/.venv/Lib/site-packages/greenlet/tests/test_leaks.py b/.venv/Lib/site-packages/greenlet/tests/test_leaks.py new file mode 100644 index 000000000..0ed43b05f --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/tests/test_leaks.py @@ -0,0 +1,448 @@ +# -*- coding: utf-8 -*- +""" +Testing scenarios that may have leaked. +""" +from __future__ import print_function, absolute_import, division + +import sys +import gc + +import time +import weakref +import threading + +import psutil + +import greenlet +from . import TestCase +from .leakcheck import fails_leakcheck +from .leakcheck import ignores_leakcheck +from .leakcheck import RUNNING_ON_GITHUB_ACTIONS +from .leakcheck import RUNNING_ON_MANYLINUX + +try: + from sys import intern +except ImportError: + # Python 2 + pass + +assert greenlet.GREENLET_USE_GC # Option to disable this was removed in 1.0 + +class HasFinalizerTracksInstances(object): + EXTANT_INSTANCES = set() + def __init__(self, msg): + self.msg = intern(msg) + self.EXTANT_INSTANCES.add(id(self)) + def __del__(self): + self.EXTANT_INSTANCES.remove(id(self)) + def __repr__(self): + return "" % ( + id(self), self.msg + ) + @classmethod + def reset(cls): + cls.EXTANT_INSTANCES.clear() + + +class TestLeaks(TestCase): + + def test_arg_refs(self): + args = ('a', 'b', 'c') + refcount_before = sys.getrefcount(args) + # pylint:disable=unnecessary-lambda + g = greenlet.greenlet( + lambda *args: greenlet.getcurrent().parent.switch(*args)) + for _ in range(100): + g.switch(*args) + self.assertEqual(sys.getrefcount(args), refcount_before) + + def test_kwarg_refs(self): + kwargs = {} + # pylint:disable=unnecessary-lambda + g = greenlet.greenlet( + lambda **kwargs: greenlet.getcurrent().parent.switch(**kwargs)) + for _ in range(100): + g.switch(**kwargs) + self.assertEqual(sys.getrefcount(kwargs), 2) + + + @staticmethod + def __recycle_threads(): + # By introducing a thread that does sleep we allow other threads, + # that have triggered their __block condition, but did not have a + # chance to deallocate their thread state yet, to finally do so. + # The way it works is by requiring a GIL switch (different thread), + # which does a GIL release (sleep), which might do a GIL switch + # to finished threads and allow them to clean up. + def worker(): + time.sleep(0.001) + t = threading.Thread(target=worker) + t.start() + time.sleep(0.001) + t.join(10) + + def test_threaded_leak(self): + gg = [] + def worker(): + # only main greenlet present + gg.append(weakref.ref(greenlet.getcurrent())) + for _ in range(2): + t = threading.Thread(target=worker) + t.start() + t.join(10) + del t + greenlet.getcurrent() # update ts_current + self.__recycle_threads() + greenlet.getcurrent() # update ts_current + gc.collect() + greenlet.getcurrent() # update ts_current + for g in gg: + self.assertIsNone(g()) + + def test_threaded_adv_leak(self): + gg = [] + def worker(): + # main and additional *finished* greenlets + ll = greenlet.getcurrent().ll = [] + def additional(): + ll.append(greenlet.getcurrent()) + for _ in range(2): + greenlet.greenlet(additional).switch() + gg.append(weakref.ref(greenlet.getcurrent())) + for _ in range(2): + t = threading.Thread(target=worker) + t.start() + t.join(10) + del t + greenlet.getcurrent() # update ts_current + self.__recycle_threads() + greenlet.getcurrent() # update ts_current + gc.collect() + greenlet.getcurrent() # update ts_current + for g in gg: + self.assertIsNone(g()) + + def assertClocksUsed(self): + used = greenlet._greenlet.get_clocks_used_doing_optional_cleanup() + self.assertGreaterEqual(used, 0) + # we don't lose the value + greenlet._greenlet.enable_optional_cleanup(True) + used2 = greenlet._greenlet.get_clocks_used_doing_optional_cleanup() + self.assertEqual(used, used2) + self.assertGreater(greenlet._greenlet.CLOCKS_PER_SEC, 1) + + def _check_issue251(self, + manually_collect_background=True, + explicit_reference_to_switch=False): + # See https://github.com/python-greenlet/greenlet/issues/251 + # Killing a greenlet (probably not the main one) + # in one thread from another thread would + # result in leaking a list (the ts_delkey list). + # We no longer use lists to hold that stuff, though. + + # For the test to be valid, even empty lists have to be tracked by the + # GC + + assert gc.is_tracked([]) + HasFinalizerTracksInstances.reset() + greenlet.getcurrent() + greenlets_before = self.count_objects(greenlet.greenlet, exact_kind=False) + + background_glet_running = threading.Event() + background_glet_killed = threading.Event() + background_greenlets = [] + + # XXX: Switching this to a greenlet subclass that overrides + # run results in all callers failing the leaktest; that + # greenlet instance is leaked. There's a bound method for + # run() living on the stack of the greenlet in g_initialstub, + # and since we don't manually switch back to the background + # greenlet to let it "fall off the end" and exit the + # g_initialstub function, it never gets cleaned up. Making the + # garbage collector aware of this bound method (making it an + # attribute of the greenlet structure and traversing into it) + # doesn't help, for some reason. + def background_greenlet(): + # Throw control back to the main greenlet. + jd = HasFinalizerTracksInstances("DELETING STACK OBJECT") + greenlet._greenlet.set_thread_local( + 'test_leaks_key', + HasFinalizerTracksInstances("DELETING THREAD STATE")) + # Explicitly keeping 'switch' in a local variable + # breaks this test in all versions + if explicit_reference_to_switch: + s = greenlet.getcurrent().parent.switch + s([jd]) + else: + greenlet.getcurrent().parent.switch([jd]) + + bg_main_wrefs = [] + + def background_thread(): + glet = greenlet.greenlet(background_greenlet) + bg_main_wrefs.append(weakref.ref(glet.parent)) + + background_greenlets.append(glet) + glet.switch() # Be sure it's active. + # Control is ours again. + del glet # Delete one reference from the thread it runs in. + background_glet_running.set() + background_glet_killed.wait(10) + + # To trigger the background collection of the dead + # greenlet, thus clearing out the contents of the list, we + # need to run some APIs. See issue 252. + if manually_collect_background: + greenlet.getcurrent() + + + t = threading.Thread(target=background_thread) + t.start() + background_glet_running.wait(10) + greenlet.getcurrent() + lists_before = self.count_objects(list, exact_kind=True) + + assert len(background_greenlets) == 1 + self.assertFalse(background_greenlets[0].dead) + # Delete the last reference to the background greenlet + # from a different thread. This puts it in the background thread's + # ts_delkey list. + del background_greenlets[:] + background_glet_killed.set() + + # Now wait for the background thread to die. + t.join(10) + del t + # As part of the fix for 252, we need to cycle the ceval.c + # interpreter loop to be sure it has had a chance to process + # the pending call. + self.wait_for_pending_cleanups() + + lists_after = self.count_objects(list, exact_kind=True) + greenlets_after = self.count_objects(greenlet.greenlet, exact_kind=False) + + # On 2.7, we observe that lists_after is smaller than + # lists_before. No idea what lists got cleaned up. All the + # Python 3 versions match exactly. + self.assertLessEqual(lists_after, lists_before) + # On versions after 3.6, we've successfully cleaned up the + # greenlet references thanks to the internal "vectorcall" + # protocol; prior to that, there is a reference path through + # the ``greenlet.switch`` method still on the stack that we + # can't reach to clean up. The C code goes through terrific + # lengths to clean that up. + if not explicit_reference_to_switch and greenlet._greenlet.get_clocks_used_doing_optional_cleanup() is not None: + # If cleanup was disabled, though, we may not find it. + self.assertEqual(greenlets_after, greenlets_before) + if manually_collect_background: + # TODO: Figure out how to make this work! + # The one on the stack is still leaking somehow + # in the non-manually-collect state. + self.assertEqual(HasFinalizerTracksInstances.EXTANT_INSTANCES, set()) + else: + # The explicit reference prevents us from collecting it + # and it isn't always found by the GC either for some + # reason. The entire frame is leaked somehow, on some + # platforms (e.g., MacPorts builds of Python (all + # versions!)), but not on other platforms (the linux and + # windows builds on GitHub actions and Appveyor). So we'd + # like to write a test that proves that the main greenlet + # sticks around, and we can on my machine (macOS 11.6, + # MacPorts builds of everything) but we can't write that + # same test on other platforms. However, hopefully iteration + # done by leakcheck will find it. + pass + + if greenlet._greenlet.get_clocks_used_doing_optional_cleanup() is not None: + self.assertClocksUsed() + + def test_issue251_killing_cross_thread_leaks_list(self): + self._check_issue251() + + def test_issue251_with_cleanup_disabled(self): + greenlet._greenlet.enable_optional_cleanup(False) + try: + self._check_issue251() + finally: + greenlet._greenlet.enable_optional_cleanup(True) + + @fails_leakcheck + def test_issue251_issue252_need_to_collect_in_background(self): + # Between greenlet 1.1.2 and the next version, this was still + # failing because the leak of the list still exists when we + # don't call a greenlet API before exiting the thread. The + # proximate cause is that neither of the two greenlets from + # the background thread are actually being destroyed, even + # though the GC is in fact visiting both objects. It's not + # clear where that leak is? For some reason the thread-local + # dict holding it isn't being cleaned up. + # + # The leak, I think, is in the CPYthon internal function that + # calls into green_switch(). The argument tuple is still on + # the C stack somewhere and can't be reached? That doesn't + # make sense, because the tuple should be collectable when + # this object goes away. + # + # Note that this test sometimes spuriously passes on Linux, + # for some reason, but I've never seen it pass on macOS. + self._check_issue251(manually_collect_background=False) + + @fails_leakcheck + def test_issue251_issue252_need_to_collect_in_background_cleanup_disabled(self): + self.expect_greenlet_leak = True + greenlet._greenlet.enable_optional_cleanup(False) + try: + self._check_issue251(manually_collect_background=False) + finally: + greenlet._greenlet.enable_optional_cleanup(True) + + @fails_leakcheck + def test_issue251_issue252_explicit_reference_not_collectable(self): + self._check_issue251( + manually_collect_background=False, + explicit_reference_to_switch=True) + + UNTRACK_ATTEMPTS = 100 + + def _only_test_some_versions(self): + # We're only looking for this problem specifically on 3.11, + # and this set of tests is relatively fragile, depending on + # OS and memory management details. So we want to run it on 3.11+ + # (obviously) but not every older 3.x version in order to reduce + # false negatives. + if sys.version_info[0] >= 3 and sys.version_info[:2] < (3, 8): + self.skipTest('Only observed on 3.11') + if sys.version_info[0] == 2 and RUNNING_ON_GITHUB_ACTIONS: + self.skipTest('Hard to get a stable pattern here') + if RUNNING_ON_MANYLINUX: + self.skipTest("Slow and not worth repeating here") + + @ignores_leakcheck + # Because we're just trying to track raw memory, not objects, and running + # the leakcheck makes an already slow test slower. + def test_untracked_memory_doesnt_increase(self): + # See https://github.com/gevent/gevent/issues/1924 + # and https://github.com/python-greenlet/greenlet/issues/328 + self._only_test_some_versions() + def f(): + return 1 + + ITER = 10000 + def run_it(): + for _ in range(ITER): + greenlet.greenlet(f).switch() + + # Establish baseline + for _ in range(3): + run_it() + + # uss: (Linux, macOS, Windows): aka "Unique Set Size", this is + # the memory which is unique to a process and which would be + # freed if the process was terminated right now. + uss_before = psutil.Process().memory_full_info().uss + + for count in range(self.UNTRACK_ATTEMPTS): + uss_before = max(uss_before, psutil.Process().memory_full_info().uss) + run_it() + + uss_after = psutil.Process().memory_full_info().uss + if uss_after <= uss_before and count > 1: + break + + self.assertLessEqual(uss_after, uss_before) + + def _check_untracked_memory_thread(self, deallocate_in_thread=True): + self._only_test_some_versions() + # Like the above test, but what if there are a bunch of + # unfinished greenlets in a thread that dies? + # Does it matter if we deallocate in the thread or not? + EXIT_COUNT = [0] + + def f(): + try: + greenlet.getcurrent().parent.switch() + except greenlet.GreenletExit: + EXIT_COUNT[0] += 1 + raise + return 1 + + ITER = 10000 + def run_it(): + glets = [] + for _ in range(ITER): + # Greenlet starts, switches back to us. + # We keep a strong reference to the greenlet though so it doesn't + # get a GreenletExit exception. + g = greenlet.greenlet(f) + glets.append(g) + g.switch() + + return glets + + test = self + + class ThreadFunc: + uss_before = uss_after = 0 + glets = () + ITER = 2 + def __call__(self): + self.uss_before = psutil.Process().memory_full_info().uss + + for _ in range(self.ITER): + self.glets += tuple(run_it()) + + for g in self.glets: + test.assertIn('suspended active', str(g)) + # Drop them. + if deallocate_in_thread: + self.glets = () + self.uss_after = psutil.Process().memory_full_info().uss + + # Establish baseline + uss_before = uss_after = None + for count in range(self.UNTRACK_ATTEMPTS): + EXIT_COUNT[0] = 0 + thread_func = ThreadFunc() + t = threading.Thread(target=thread_func) + t.start() + t.join(30) + self.assertFalse(t.is_alive()) + + if uss_before is None: + uss_before = thread_func.uss_before + + uss_before = max(uss_before, thread_func.uss_before) + if deallocate_in_thread: + self.assertEqual(thread_func.glets, ()) + self.assertEqual(EXIT_COUNT[0], ITER * thread_func.ITER) + + del thread_func # Deallocate the greenlets; but this won't raise into them + del t + if not deallocate_in_thread: + self.assertEqual(EXIT_COUNT[0], 0) + if deallocate_in_thread: + self.wait_for_pending_cleanups() + + uss_after = psutil.Process().memory_full_info().uss + # See if we achieve a non-growth state at some point. Break when we do. + if uss_after <= uss_before and count > 1: + break + + self.wait_for_pending_cleanups() + uss_after = psutil.Process().memory_full_info().uss + self.assertLessEqual(uss_after, uss_before, "after attempts %d" % (count,)) + + @ignores_leakcheck + # Because we're just trying to track raw memory, not objects, and running + # the leakcheck makes an already slow test slower. + def test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_thread(self): + self._check_untracked_memory_thread(deallocate_in_thread=True) + + @ignores_leakcheck + # Because the main greenlets from the background threads do not exit in a timely fashion, + # we fail the object-based leakchecks. + def test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_main(self): + self._check_untracked_memory_thread(deallocate_in_thread=False) + +if __name__ == '__main__': + __import__('unittest').main() diff --git a/.venv/Lib/site-packages/greenlet/tests/test_stack_saved.py b/.venv/Lib/site-packages/greenlet/tests/test_stack_saved.py new file mode 100644 index 000000000..b362bf95a --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/tests/test_stack_saved.py @@ -0,0 +1,19 @@ +import greenlet +from . import TestCase + + +class Test(TestCase): + + def test_stack_saved(self): + main = greenlet.getcurrent() + self.assertEqual(main._stack_saved, 0) + + def func(): + main.switch(main._stack_saved) + + g = greenlet.greenlet(func) + x = g.switch() + self.assertGreater(x, 0) + self.assertGreater(g._stack_saved, 0) + g.switch() + self.assertEqual(g._stack_saved, 0) diff --git a/.venv/Lib/site-packages/greenlet/tests/test_throw.py b/.venv/Lib/site-packages/greenlet/tests/test_throw.py new file mode 100644 index 000000000..90d657a2f --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/tests/test_throw.py @@ -0,0 +1,129 @@ +import sys + + +from greenlet import greenlet +from . import TestCase + +def switch(*args): + return greenlet.getcurrent().parent.switch(*args) + + +class ThrowTests(TestCase): + def test_class(self): + def f(): + try: + switch("ok") + except RuntimeError: + switch("ok") + return + switch("fail") + g = greenlet(f) + res = g.switch() + self.assertEqual(res, "ok") + res = g.throw(RuntimeError) + self.assertEqual(res, "ok") + + def test_val(self): + def f(): + try: + switch("ok") + except RuntimeError: + val = sys.exc_info()[1] + if str(val) == "ciao": + switch("ok") + return + switch("fail") + + g = greenlet(f) + res = g.switch() + self.assertEqual(res, "ok") + res = g.throw(RuntimeError("ciao")) + self.assertEqual(res, "ok") + + g = greenlet(f) + res = g.switch() + self.assertEqual(res, "ok") + res = g.throw(RuntimeError, "ciao") + self.assertEqual(res, "ok") + + def test_kill(self): + def f(): + switch("ok") + switch("fail") + g = greenlet(f) + res = g.switch() + self.assertEqual(res, "ok") + res = g.throw() + self.assertTrue(isinstance(res, greenlet.GreenletExit)) + self.assertTrue(g.dead) + res = g.throw() # immediately eaten by the already-dead greenlet + self.assertTrue(isinstance(res, greenlet.GreenletExit)) + + def test_throw_goes_to_original_parent(self): + main = greenlet.getcurrent() + + def f1(): + try: + main.switch("f1 ready to catch") + except IndexError: + return "caught" + else: + return "normal exit" + + def f2(): + main.switch("from f2") + + g1 = greenlet(f1) + g2 = greenlet(f2, parent=g1) + with self.assertRaises(IndexError): + g2.throw(IndexError) + self.assertTrue(g2.dead) + self.assertTrue(g1.dead) + + g1 = greenlet(f1) + g2 = greenlet(f2, parent=g1) + res = g1.switch() + self.assertEqual(res, "f1 ready to catch") + res = g2.throw(IndexError) + self.assertEqual(res, "caught") + self.assertTrue(g2.dead) + self.assertTrue(g1.dead) + + g1 = greenlet(f1) + g2 = greenlet(f2, parent=g1) + res = g1.switch() + self.assertEqual(res, "f1 ready to catch") + res = g2.switch() + self.assertEqual(res, "from f2") + res = g2.throw(IndexError) + self.assertEqual(res, "caught") + self.assertTrue(g2.dead) + self.assertTrue(g1.dead) + + def test_non_traceback_param(self): + with self.assertRaises(TypeError) as exc: + greenlet.getcurrent().throw( + Exception, + Exception(), + self + ) + self.assertEqual(str(exc.exception), + "throw() third argument must be a traceback object") + + def test_instance_of_wrong_type(self): + with self.assertRaises(TypeError) as exc: + greenlet.getcurrent().throw( + Exception(), + BaseException() + ) + + self.assertEqual(str(exc.exception), + "instance exception may not have a separate value") + + def test_not_throwable(self): + with self.assertRaises(TypeError) as exc: + greenlet.getcurrent().throw( + "abc" + ) + self.assertEqual(str(exc.exception), + "exceptions must be classes, or instances, not str") diff --git a/.venv/Lib/site-packages/greenlet/tests/test_tracing.py b/.venv/Lib/site-packages/greenlet/tests/test_tracing.py new file mode 100644 index 000000000..de84dbca8 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/tests/test_tracing.py @@ -0,0 +1,278 @@ +from __future__ import print_function +import sys +import greenlet + +from . import TestCase + +class SomeError(Exception): + pass + +class GreenletTracer(object): + oldtrace = None + + def __init__(self, error_on_trace=False): + self.actions = [] + self.error_on_trace = error_on_trace + + def __call__(self, *args): + self.actions.append(args) + if self.error_on_trace: + raise SomeError + + def __enter__(self): + self.oldtrace = greenlet.settrace(self) + return self.actions + + def __exit__(self, *args): + greenlet.settrace(self.oldtrace) + + +class TestGreenletTracing(TestCase): + """ + Tests of ``greenlet.settrace()`` + """ + + def test_a_greenlet_tracing(self): + main = greenlet.getcurrent() + def dummy(): + pass + def dummyexc(): + raise SomeError() + + with GreenletTracer() as actions: + g1 = greenlet.greenlet(dummy) + g1.switch() + g2 = greenlet.greenlet(dummyexc) + self.assertRaises(SomeError, g2.switch) + + self.assertEqual(actions, [ + ('switch', (main, g1)), + ('switch', (g1, main)), + ('switch', (main, g2)), + ('throw', (g2, main)), + ]) + + def test_b_exception_disables_tracing(self): + main = greenlet.getcurrent() + def dummy(): + main.switch() + g = greenlet.greenlet(dummy) + g.switch() + with GreenletTracer(error_on_trace=True) as actions: + self.assertRaises(SomeError, g.switch) + self.assertEqual(greenlet.gettrace(), None) + + self.assertEqual(actions, [ + ('switch', (main, g)), + ]) + + def test_set_same_tracer_twice(self): + # https://github.com/python-greenlet/greenlet/issues/332 + # Our logic in asserting that the tracefunction should + # gain a reference was incorrect if the same tracefunction was set + # twice. + tracer = GreenletTracer() + with tracer: + greenlet.settrace(tracer) + + +class PythonTracer(object): + oldtrace = None + + def __init__(self): + self.actions = [] + + def __call__(self, frame, event, arg): + # Record the co_name so we have an idea what function we're in. + self.actions.append((event, frame.f_code.co_name)) + + def __enter__(self): + self.oldtrace = sys.setprofile(self) + return self.actions + + def __exit__(self, *args): + sys.setprofile(self.oldtrace) + +def tpt_callback(): + return 42 + +class TestPythonTracing(TestCase): + """ + Tests of the interaction of ``sys.settrace()`` + with greenlet facilities. + + NOTE: Most of this is probably CPython specific. + """ + + maxDiff = None + + def test_trace_events_trivial(self): + with PythonTracer() as actions: + tpt_callback() + # If we use the sys.settrace instead of setprofile, we get + # this: + + # self.assertEqual(actions, [ + # ('call', 'tpt_callback'), + # ('call', '__exit__'), + # ]) + + self.assertEqual(actions, [ + ('return', '__enter__'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('call', '__exit__'), + ('c_call', '__exit__'), + ]) + + def _trace_switch(self, glet): + with PythonTracer() as actions: + glet.switch() + return actions + + def _check_trace_events_func_already_set(self, glet): + actions = self._trace_switch(glet) + self.assertEqual(actions, [ + ('return', '__enter__'), + ('c_call', '_trace_switch'), + ('call', 'run'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('return', 'run'), + ('c_return', '_trace_switch'), + ('call', '__exit__'), + ('c_call', '__exit__'), + ]) + + def test_trace_events_into_greenlet_func_already_set(self): + def run(): + return tpt_callback() + + self._check_trace_events_func_already_set(greenlet.greenlet(run)) + + def test_trace_events_into_greenlet_subclass_already_set(self): + class X(greenlet.greenlet): + def run(self): + return tpt_callback() + self._check_trace_events_func_already_set(X()) + + def _check_trace_events_from_greenlet_sets_profiler(self, g, tracer): + g.switch() + tpt_callback() + tracer.__exit__() + self.assertEqual(tracer.actions, [ + ('return', '__enter__'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('return', 'run'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('call', '__exit__'), + ('c_call', '__exit__'), + ]) + + + def test_trace_events_from_greenlet_func_sets_profiler(self): + tracer = PythonTracer() + def run(): + tracer.__enter__() + return tpt_callback() + + self._check_trace_events_from_greenlet_sets_profiler(greenlet.greenlet(run), + tracer) + + def test_trace_events_from_greenlet_subclass_sets_profiler(self): + tracer = PythonTracer() + class X(greenlet.greenlet): + def run(self): + tracer.__enter__() + return tpt_callback() + + self._check_trace_events_from_greenlet_sets_profiler(X(), tracer) + + + def test_trace_events_multiple_greenlets_switching(self): + tracer = PythonTracer() + + g1 = None + g2 = None + + def g1_run(): + tracer.__enter__() + tpt_callback() + g2.switch() + tpt_callback() + return 42 + + def g2_run(): + tpt_callback() + tracer.__exit__() + tpt_callback() + g1.switch() + + g1 = greenlet.greenlet(g1_run) + g2 = greenlet.greenlet(g2_run) + + x = g1.switch() + self.assertEqual(x, 42) + tpt_callback() # ensure not in the trace + self.assertEqual(tracer.actions, [ + ('return', '__enter__'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('c_call', 'g1_run'), + ('call', 'g2_run'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('call', '__exit__'), + ('c_call', '__exit__'), + ]) + + def test_trace_events_multiple_greenlets_switching_siblings(self): + # Like the first version, but get both greenlets running first + # as "siblings" and then establish the tracing. + tracer = PythonTracer() + + g1 = None + g2 = None + + def g1_run(): + greenlet.getcurrent().parent.switch() + tracer.__enter__() + tpt_callback() + g2.switch() + tpt_callback() + return 42 + + def g2_run(): + greenlet.getcurrent().parent.switch() + + tpt_callback() + tracer.__exit__() + tpt_callback() + g1.switch() + + g1 = greenlet.greenlet(g1_run) + g2 = greenlet.greenlet(g2_run) + + # Start g1 + g1.switch() + # And it immediately returns control to us. + # Start g2 + g2.switch() + # Which also returns. Now kick of the real part of the + # test. + x = g1.switch() + self.assertEqual(x, 42) + + tpt_callback() # ensure not in the trace + self.assertEqual(tracer.actions, [ + ('return', '__enter__'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('c_call', 'g1_run'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('call', '__exit__'), + ('c_call', '__exit__'), + ]) diff --git a/.venv/Lib/site-packages/greenlet/tests/test_version.py b/.venv/Lib/site-packages/greenlet/tests/test_version.py new file mode 100644 index 000000000..96c17cf17 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/tests/test_version.py @@ -0,0 +1,41 @@ +#! /usr/bin/env python +from __future__ import absolute_import +from __future__ import print_function + +import sys +import os +from unittest import TestCase as NonLeakingTestCase + +import greenlet + +# No reason to run this multiple times under leakchecks, +# it doesn't do anything. +class VersionTests(NonLeakingTestCase): + def test_version(self): + def find_dominating_file(name): + if os.path.exists(name): + return name + + tried = [] + here = os.path.abspath(os.path.dirname(__file__)) + for i in range(10): + up = ['..'] * i + path = [here] + up + [name] + fname = os.path.join(*path) + fname = os.path.abspath(fname) + tried.append(fname) + if os.path.exists(fname): + return fname + raise AssertionError("Could not find file " + name + "; checked " + str(tried)) + + try: + setup_py = find_dominating_file('setup.py') + except AssertionError as e: + self.skipTest("Unable to find setup.py; must be out of tree. " + str(e)) + + + invoke_setup = "%s %s --version" % (sys.executable, setup_py) + with os.popen(invoke_setup) as f: + sversion = f.read().strip() + + self.assertEqual(sversion, greenlet.__version__) diff --git a/.venv/Lib/site-packages/greenlet/tests/test_weakref.py b/.venv/Lib/site-packages/greenlet/tests/test_weakref.py new file mode 100644 index 000000000..916ef8ae5 --- /dev/null +++ b/.venv/Lib/site-packages/greenlet/tests/test_weakref.py @@ -0,0 +1,35 @@ +import gc +import weakref +import unittest + +import greenlet +from . import TestCase + +class WeakRefTests(TestCase): + def test_dead_weakref(self): + def _dead_greenlet(): + g = greenlet.greenlet(lambda: None) + g.switch() + return g + o = weakref.ref(_dead_greenlet()) + gc.collect() + self.assertEqual(o(), None) + + def test_inactive_weakref(self): + o = weakref.ref(greenlet.greenlet()) + gc.collect() + self.assertEqual(o(), None) + + def test_dealloc_weakref(self): + seen = [] + def worker(): + try: + greenlet.getcurrent().parent.switch() + finally: + seen.append(g()) + g = greenlet.greenlet(worker) + g.switch() + g2 = greenlet.greenlet(lambda: None, g) + g = weakref.ref(g2) + g2 = None + self.assertEqual(seen, [None]) diff --git a/.venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/INSTALLER b/.venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/.venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/LICENSE.rst b/.venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/LICENSE.rst new file mode 100644 index 000000000..7b190ca67 --- /dev/null +++ b/.venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2011 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/.venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/METADATA b/.venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/METADATA new file mode 100644 index 000000000..1d935ed3d --- /dev/null +++ b/.venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/METADATA @@ -0,0 +1,97 @@ +Metadata-Version: 2.1 +Name: itsdangerous +Version: 2.1.2 +Summary: Safely pass data to untrusted environments and back. +Home-page: https://palletsprojects.com/p/itsdangerous/ +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://itsdangerous.palletsprojects.com/ +Project-URL: Changes, https://itsdangerous.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/itsdangerous/ +Project-URL: Issue Tracker, https://github.com/pallets/itsdangerous/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +Project-URL: Chat, https://discord.gg/pallets +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst + +ItsDangerous +============ + +... so better sign this + +Various helpers to pass data to untrusted environments and to get it +back safe and sound. Data is cryptographically signed to ensure that a +token has not been tampered with. + +It's possible to customize how data is serialized. Data is compressed as +needed. A timestamp can be added and verified automatically while +loading a token. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + pip install -U itsdangerous + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +A Simple Example +---------------- + +Here's how you could generate a token for transmitting a user's id and +name between web requests. + +.. code-block:: python + + from itsdangerous import URLSafeSerializer + auth_s = URLSafeSerializer("secret key", "auth") + token = auth_s.dumps({"id": 5, "name": "itsdangerous"}) + + print(token) + # eyJpZCI6NSwibmFtZSI6Iml0c2Rhbmdlcm91cyJ9.6YP6T0BaO67XP--9UzTrmurXSmg + + data = auth_s.loads(token) + print(data["name"]) + # itsdangerous + + +Donate +------ + +The Pallets organization develops and supports ItsDangerous and other +popular packages. In order to grow the community of contributors and +users, and allow the maintainers to devote more time to the projects, +`please donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://itsdangerous.palletsprojects.com/ +- Changes: https://itsdangerous.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/ItsDangerous/ +- Source Code: https://github.com/pallets/itsdangerous/ +- Issue Tracker: https://github.com/pallets/itsdangerous/issues/ +- Website: https://palletsprojects.com/p/itsdangerous/ +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets + + diff --git a/.venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/RECORD b/.venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/RECORD new file mode 100644 index 000000000..623d2b494 --- /dev/null +++ b/.venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/RECORD @@ -0,0 +1,23 @@ +itsdangerous-2.1.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +itsdangerous-2.1.2.dist-info/LICENSE.rst,sha256=Y68JiRtr6K0aQlLtQ68PTvun_JSOIoNnvtfzxa4LCdc,1475 +itsdangerous-2.1.2.dist-info/METADATA,sha256=ThrHIJQ_6XlfbDMCAVe_hawT7IXiIxnTBIDrwxxtucQ,2928 +itsdangerous-2.1.2.dist-info/RECORD,, +itsdangerous-2.1.2.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +itsdangerous-2.1.2.dist-info/top_level.txt,sha256=gKN1OKLk81i7fbWWildJA88EQ9NhnGMSvZqhfz9ICjk,13 +itsdangerous/__init__.py,sha256=n4mkyjlIVn23pgsgCIw0MJKPdcHIetyeRpe5Fwsn8qg,876 +itsdangerous/__pycache__/__init__.cpython-311.pyc,, +itsdangerous/__pycache__/_json.cpython-311.pyc,, +itsdangerous/__pycache__/encoding.cpython-311.pyc,, +itsdangerous/__pycache__/exc.cpython-311.pyc,, +itsdangerous/__pycache__/serializer.cpython-311.pyc,, +itsdangerous/__pycache__/signer.cpython-311.pyc,, +itsdangerous/__pycache__/timed.cpython-311.pyc,, +itsdangerous/__pycache__/url_safe.cpython-311.pyc,, +itsdangerous/_json.py,sha256=wIhs_7-_XZolmyr-JvKNiy_LgAcfevYR0qhCVdlIhg8,450 +itsdangerous/encoding.py,sha256=pgh86snHC76dPLNCnPlrjR5SaYL_M8H-gWRiiLNbhCU,1419 +itsdangerous/exc.py,sha256=VFxmP2lMoSJFqxNMzWonqs35ROII4-fvCBfG0v1Tkbs,3206 +itsdangerous/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +itsdangerous/serializer.py,sha256=zgZ1-U705jHDpt62x_pmLJdryEKDNAbt5UkJtnkcCSw,11144 +itsdangerous/signer.py,sha256=QUH0iX0in-OTptMAXKU5zWMwmOCXn1fsDsubXiGdFN4,9367 +itsdangerous/timed.py,sha256=5CBWLds4Nm8-3bFVC8RxNzFjx6PSwjch8wuZ5cwcHFI,8174 +itsdangerous/url_safe.py,sha256=5bC4jSKOjWNRkWrFseifWVXUnHnPgwOLROjiOwb-eeo,2402 diff --git a/.venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/WHEEL b/.venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/WHEEL new file mode 100644 index 000000000..becc9a66e --- /dev/null +++ b/.venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/.venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/top_level.txt b/.venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/top_level.txt new file mode 100644 index 000000000..e163955e8 --- /dev/null +++ b/.venv/Lib/site-packages/itsdangerous-2.1.2.dist-info/top_level.txt @@ -0,0 +1 @@ +itsdangerous diff --git a/.venv/Lib/site-packages/itsdangerous/__init__.py b/.venv/Lib/site-packages/itsdangerous/__init__.py new file mode 100644 index 000000000..fdb2dfd00 --- /dev/null +++ b/.venv/Lib/site-packages/itsdangerous/__init__.py @@ -0,0 +1,19 @@ +from .encoding import base64_decode as base64_decode +from .encoding import base64_encode as base64_encode +from .encoding import want_bytes as want_bytes +from .exc import BadData as BadData +from .exc import BadHeader as BadHeader +from .exc import BadPayload as BadPayload +from .exc import BadSignature as BadSignature +from .exc import BadTimeSignature as BadTimeSignature +from .exc import SignatureExpired as SignatureExpired +from .serializer import Serializer as Serializer +from .signer import HMACAlgorithm as HMACAlgorithm +from .signer import NoneAlgorithm as NoneAlgorithm +from .signer import Signer as Signer +from .timed import TimedSerializer as TimedSerializer +from .timed import TimestampSigner as TimestampSigner +from .url_safe import URLSafeSerializer as URLSafeSerializer +from .url_safe import URLSafeTimedSerializer as URLSafeTimedSerializer + +__version__ = "2.1.2" diff --git a/.venv/Lib/site-packages/itsdangerous/__pycache__/__init__.cpython-311.pyc b/.venv/Lib/site-packages/itsdangerous/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f8840b7c9219e4c0ea4353adc0ae3b7826e351b9 GIT binary patch literal 1164 zcmZvaO>fgM7{{Gr>ozzbE+C;ET3{L+(1aL+X@@Z(x(UgOlsSzl)|?mF>DYGS zTkrumAihmbDC!A`6E~z?&`vzI#xz5nzaIUbzaKx2Eq`%c2f_IL`7q>Vgnp>x?#4cy0l%^kiRt>6{SUEo!` z3f#jt!u}WymVa7sxPdiy10w0;bw8w&B&6328ebaD2NGv~aGFsG)3xU$d_gh-SO?sp zB%}fo2a?z1lqV#FtO?neO=FVHglgJ>e4j+DpVlM%k*R-sw%CiV5?A9LA@@~fG~ID)saL~8C9wOS-7gCr9xZT zl}sH#bd=FmhCLJ9m+-Tqr@X%M8oqx_g=9(W`(M#HSm+|ydg2|xCeqs>0Skziq%0nbeNLK5t&lyu}p>}o>Gy_O%>=~ZmK|o+*E;v xxv2s@%1teD9^}YSf!1>ee4_k zGC5g9K(BwkO@GG-{jG!%SwqlY0I-WFqPT^sSg%IaG|-ob8as%Zdj>-LFb7n%C|*In z^{)~u^`TZTg`v=Y2w)d6eOuL_xN0(s8q97wBXd?@Zo`-ziQolxFO0;7MXeoc55)bE z3RR16hke?LI%g!46&emLoI5u`U5NLBEQL3cc1r5m*DE(G_pjdKBuyFj2v72udQFkU zUOS7ql^(bQkjVq-3*|5GozcvYf|tDCw9?Kx+0c0oz5{slDbH zZ=pTF`(qgb!xi6w(pRSeU>w$VRRGY@`z^7+Bk+~L$**PZKw7D+RyHKnt0kMK2drW7jr37Gw# zfbF6!+=2BxQA~}qy@lUyYf|e?+f0>vNX>D7ZlMN_;GU=Wq3Tn+B1M0vOCa${U_$xuJg%M;p8@tp)${>n zEtY|8qZjTwf4Z}OxU)~n&ptkI7Y^NpuDftF)?R*AJa88e-NmlE_?NEmVt2}i(fMSs zc3q#VI#&FWbi*(vZ5D>I7>0vB1zZZlJ2`0$cM4%hle$uijAT*0&9e1`N+Zmqy&6Z* zU?z06v}>Et($c&h4?e!mN00d9 zA3A1dwNpHN@6#Rv&2!^7M}rgg(nQYmPM{C;9Kb!pv@bon`uMXR0?_&P>Gv8uH}!JD z#s|UbL^}vnh3DJSQV(bF#hh$2jp8-_{wR9>fkLW+I;~@OX;8Q?_=liV&r93{)-y52 dM`)%y8b|12cQks=1P0&d*-NE+^*0OJf6bSM)NSjxyG zM5JQ)x{^^aqVjsAeGHA#zSYopn?#vdA0i_}p)nGnQ4)pT2OLon`#79Yi3;2_}O?P54a2Is=4tmfsgCRsi>qBjtBzo49G`apv zdo?o*-17QJnI@+f0hTvrALCcJhAv%7jK@uc>mOMlIfF1{phJk*L;ANB=eZ<+9 z9&w3M*pDn2Ckl9D12zFQ9EloHZiO<%1RacblW;J4C25Dri8#j+X7rU0sLrTeDLQ;TSTq=ofg^O=Sf#pC z(knLAO-sM}&YSj(SUBLCUP#HpbiR@om-&MgR^(f9`MKHPVu(L}aXEz<&mWs_(-}`g zUkf(n0!B6lb3BRcmjHkdqNsnYuDIH9Pdi>)+*1cVb*i!GsxNx#ix1T^57aY1%)071 zPd(R^&#^(+)Mb6BPeF`(FzB^D!6fv(bQi4o-H}Ck#1gsF553k`5eZingsO0MRYPbC z^&yAfbJ*68&g$K{jHZyo!~C#0qK*c{YUl)F!&}&a6Wfg_-5%Yas6iuQB{!0h`BRYYSw3Lbj5g`?+#fE{sD<%R#{l1l3WqO&{CqMQ(qgV;X zjGqp7@;LD^wRslkJ+TrTz$Rho7BoEV;XBo)I>|Hs{8O;k zKinKS>-Nuj{j>L;Z$^Lp7+OmL9>6xQ?f**7V{{)6&QDAChZ6IX(*4OWjH^;QcY!?% z4As!Zx2sb*XXcVoEE@SDeeXSC_-m(hm|UrpVaBwaYu9|qs$B1iWFA$#A1ngsjpXh) zX>`^f;11f4)rTdKz+i4)%fY=lrxcVzUn#cpbqaQO=4-r@kNq50f5|z12B3!a)UkTf zRVO@k;-PxtfqJ6xuB)a!HQkicB02qt(AQyIx7u1FmRUQJ&i<{CVFjQ{!Z6S>1e zYZS{L7B-izDF(?HtxU=~EZvh40!{p@$$; I34~|<2O);G00000 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/itsdangerous/__pycache__/exc.cpython-311.pyc b/.venv/Lib/site-packages/itsdangerous/__pycache__/exc.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1ac43b3011a10c6a5666bc177acb1b0e5c8ba907 GIT binary patch literal 5005 zcmcIo-ESLN6~AM9?6G4fY11|-{hAU=ak_DLp$Ilw5X*L95vzbm`H(lO$;5M=OxK<< z_m0yh3Q`^_2vQ#^0csz3sDxCgDk1)qEQ&;A327yscyp8>t@erEx#JmsC84`ortz73 z@40h7&i(z)Ik$f<6mksD$A4OKew}CRUsQ=6y;C?~8e@-{!yK)~${OB@TB4pPCp5;j zyUD0K%BiS)J}R)X-q$DHqsb)L_nDJ?z?>9MKf^dL;<3tx(&^BpxiO&2DqRLTgJ%bH zIi<@&m*cqs-H6hSK$jo-F0XV2=thU;D>&K$D~|n}_B3DAT83i>JaFs067Ld)Xzd5L zQ27n)#g(nf2}dg@odi!+6Wgq+VZZsZjvb@!=nqom^ftS%l{1(j-O7B|c5d5&z45!B z*skP`=~m5U+c7brZTeNy_SQ}5i@>~ROOtyQzv%^BaHnM6S#_m}zhIT)3(0dPo~kcQ zyH+##{R(dcuJ4iF4$L0}^0w`*aN#$l>F}!Saaqc#Pf8_ojSGpsw&QSTZq9tQ^xD^z zs+Fm8DeVEr@FJ?Pr#+guk!@Ep z7T9xbzL;$3vf1FGWmuN$xq)SgG)6&tO7dD&Ra#lgs?=;LElbj(Ompj#_uraZ{HesA z7T>X#-DP{xZ*XtHZ;A?E{2uy#F#B`9Jo{#&F?**O_`sHMibAo^^Kch0R8Eo}^~^2-n(Z?S(Gh2Lf#X8vJJ{oR;)GWnr# zb=SDMV_e;vyu6)ynBT^~1N3CAwBSKgc$L@`Xr!_-?>GvN*(SS-clazYVW3phLOW<; z1T{$?n4$pL%D@VNu&j--?($T_1a+i^Z?V0xiHDmz#sx8oYSAF$dUl;#Rx4*&b>C^$ zsGPT~UpDPpM}u)4zk=o@MpFh5r)a)H$M_Xqt6A1_O~9dq3;K>)kRXSm1g%@T5HL^l zuboKgMw^kyC-f^%lWm6A@xsvbi%%xn46m0EYJY0(3Z{*p*u|C5G(_68ljJE-Rj;NL zb@c~@9=c{)dDwNqUGZ!j8{fFr<*aSWsM&OUE=|u5%(@*^R!j3CP%{mCz2@6ag$_4* zsH_hAbL3KDkV_$Gk|K-A!o$0OQZc3AqZTKqAv`>C=x`)k;rS`7pY7dr4EQggqx=fQ z34m{pvM=3;ARiux0D<^ zAwsOvO8T%K#ij$I>|l-q#3ozgF;w5a-*AzfY=~aOb{!*OR|a;yL3xW`bGV@F#50$c z>h^sL0e5LB%xe@T(Wi@H%7x|-fE9ZC=n)|p{_F^+@|=a+qVOol!b*G#1$h}F3PoG2 z$I{B&B*IVWt3Hd6AEoEu4Tz)I5B?iH{MV7urmKcxdj@RJD7G80UAC14OyA))OtJCT zL8F1hK$H)ADn3*n0j5i@#X@3D%O|Bv_B zOu?5VqX{XE3`1Y4C-fDe7UTko=|P7Qt3t0rxh8p)KDTl@KCjrH{1E-*HzCNMjGo|6 z3^rXvFdP9*Z@f;9MI1@|G!?R?M!mtXAp=XJrBbac4OQEPNNW4W$`&GEK25{a-?aG@|wN(I^7P z!Dq_EayW<|hZ&W93qGosJe^Fdhc+Fi;QCYpsT57KfPIb1ey6Ttl| zW?syVS4`Zp!mkCVNo=$3N|o%XQI>gdk8@9r-lZXiQp3i)q&0C26*8uKWm97)e)^S4 zQ^22^PE)wvib-puH>Q-hxIp21ChmoEb`XfUrD&*-eDI5Eq!aFUov2T2sKm5Eh065% zJa2d}k(DY|_GYEjaBNmO(FH(E#VS6KHy}X8<1S%GvM=-#$ET&@6G6XQsX>qIjM%1QD1TUot6l?drXlNCo>>0rG9NQf_@8fF^PD7BJrB7Ii5 zNcQdMzXHNN5bIRtta6SpBr1QQwm=uyaC{1wpBQh17s79guc1nrfV>UaPHLLA$0l~7 zzdd$or~mJx!q~(2o}B*Ux!r=fmD^Lb^Sg!Vtz0{u*KmIu7TfMVwH|g=mq#>Y@WbNK zH}eeXr R92Soz_o?;p2$iz(e*yF!K^Xu5 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/itsdangerous/__pycache__/serializer.cpython-311.pyc b/.venv/Lib/site-packages/itsdangerous/__pycache__/serializer.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d600540e2dc4a45dfeb12dcf255baa792ecb1f8c GIT binary patch literal 13648 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/itsdangerous/__pycache__/signer.cpython-311.pyc b/.venv/Lib/site-packages/itsdangerous/__pycache__/signer.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b6546a56f198951e3c82f0f373be93e60b858126 GIT binary patch literal 12355 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 JP|IlR{{X0dqmlps literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/itsdangerous/__pycache__/timed.cpython-311.pyc b/.venv/Lib/site-packages/itsdangerous/__pycache__/timed.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..433bb8e01788d6bc86793e3d792d7564d48fd69f GIT binary patch literal 10081 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/itsdangerous/__pycache__/url_safe.cpython-311.pyc b/.venv/Lib/site-packages/itsdangerous/__pycache__/url_safe.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5e1c1eb058772ee683c35582db4c8aa08c7110c1 GIT binary patch literal 4009 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 y2|1ta1*?U}IQpbVVuB< _t.Any: + return _json.loads(payload) + + @staticmethod + def dumps(obj: _t.Any, **kwargs: _t.Any) -> str: + kwargs.setdefault("ensure_ascii", False) + kwargs.setdefault("separators", (",", ":")) + return _json.dumps(obj, **kwargs) diff --git a/.venv/Lib/site-packages/itsdangerous/encoding.py b/.venv/Lib/site-packages/itsdangerous/encoding.py new file mode 100644 index 000000000..edb04d1a6 --- /dev/null +++ b/.venv/Lib/site-packages/itsdangerous/encoding.py @@ -0,0 +1,54 @@ +import base64 +import string +import struct +import typing as _t + +from .exc import BadData + +_t_str_bytes = _t.Union[str, bytes] + + +def want_bytes( + s: _t_str_bytes, encoding: str = "utf-8", errors: str = "strict" +) -> bytes: + if isinstance(s, str): + s = s.encode(encoding, errors) + + return s + + +def base64_encode(string: _t_str_bytes) -> bytes: + """Base64 encode a string of bytes or text. The resulting bytes are + safe to use in URLs. + """ + string = want_bytes(string) + return base64.urlsafe_b64encode(string).rstrip(b"=") + + +def base64_decode(string: _t_str_bytes) -> bytes: + """Base64 decode a URL-safe string of bytes or text. The result is + bytes. + """ + string = want_bytes(string, encoding="ascii", errors="ignore") + string += b"=" * (-len(string) % 4) + + try: + return base64.urlsafe_b64decode(string) + except (TypeError, ValueError) as e: + raise BadData("Invalid base64-encoded data") from e + + +# The alphabet used by base64.urlsafe_* +_base64_alphabet = f"{string.ascii_letters}{string.digits}-_=".encode("ascii") + +_int64_struct = struct.Struct(">Q") +_int_to_bytes = _int64_struct.pack +_bytes_to_int = _t.cast("_t.Callable[[bytes], _t.Tuple[int]]", _int64_struct.unpack) + + +def int_to_bytes(num: int) -> bytes: + return _int_to_bytes(num).lstrip(b"\x00") + + +def bytes_to_int(bytestr: bytes) -> int: + return _bytes_to_int(bytestr.rjust(8, b"\x00"))[0] diff --git a/.venv/Lib/site-packages/itsdangerous/exc.py b/.venv/Lib/site-packages/itsdangerous/exc.py new file mode 100644 index 000000000..c38a6af52 --- /dev/null +++ b/.venv/Lib/site-packages/itsdangerous/exc.py @@ -0,0 +1,107 @@ +import typing as _t +from datetime import datetime + +_t_opt_any = _t.Optional[_t.Any] +_t_opt_exc = _t.Optional[Exception] + + +class BadData(Exception): + """Raised if bad data of any sort was encountered. This is the base + for all exceptions that ItsDangerous defines. + + .. versionadded:: 0.15 + """ + + def __init__(self, message: str): + super().__init__(message) + self.message = message + + def __str__(self) -> str: + return self.message + + +class BadSignature(BadData): + """Raised if a signature does not match.""" + + def __init__(self, message: str, payload: _t_opt_any = None): + super().__init__(message) + + #: The payload that failed the signature test. In some + #: situations you might still want to inspect this, even if + #: you know it was tampered with. + #: + #: .. versionadded:: 0.14 + self.payload: _t_opt_any = payload + + +class BadTimeSignature(BadSignature): + """Raised if a time-based signature is invalid. This is a subclass + of :class:`BadSignature`. + """ + + def __init__( + self, + message: str, + payload: _t_opt_any = None, + date_signed: _t.Optional[datetime] = None, + ): + super().__init__(message, payload) + + #: If the signature expired this exposes the date of when the + #: signature was created. This can be helpful in order to + #: tell the user how long a link has been gone stale. + #: + #: .. versionchanged:: 2.0 + #: The datetime value is timezone-aware rather than naive. + #: + #: .. versionadded:: 0.14 + self.date_signed = date_signed + + +class SignatureExpired(BadTimeSignature): + """Raised if a signature timestamp is older than ``max_age``. This + is a subclass of :exc:`BadTimeSignature`. + """ + + +class BadHeader(BadSignature): + """Raised if a signed header is invalid in some form. This only + happens for serializers that have a header that goes with the + signature. + + .. versionadded:: 0.24 + """ + + def __init__( + self, + message: str, + payload: _t_opt_any = None, + header: _t_opt_any = None, + original_error: _t_opt_exc = None, + ): + super().__init__(message, payload) + + #: If the header is actually available but just malformed it + #: might be stored here. + self.header: _t_opt_any = header + + #: If available, the error that indicates why the payload was + #: not valid. This might be ``None``. + self.original_error: _t_opt_exc = original_error + + +class BadPayload(BadData): + """Raised if a payload is invalid. This could happen if the payload + is loaded despite an invalid signature, or if there is a mismatch + between the serializer and deserializer. The original exception + that occurred during loading is stored on as :attr:`original_error`. + + .. versionadded:: 0.15 + """ + + def __init__(self, message: str, original_error: _t_opt_exc = None): + super().__init__(message) + + #: If available, the error that indicates why the payload was + #: not valid. This might be ``None``. + self.original_error: _t_opt_exc = original_error diff --git a/.venv/Lib/site-packages/itsdangerous/py.typed b/.venv/Lib/site-packages/itsdangerous/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/.venv/Lib/site-packages/itsdangerous/serializer.py b/.venv/Lib/site-packages/itsdangerous/serializer.py new file mode 100644 index 000000000..9f4a84a17 --- /dev/null +++ b/.venv/Lib/site-packages/itsdangerous/serializer.py @@ -0,0 +1,295 @@ +import json +import typing as _t + +from .encoding import want_bytes +from .exc import BadPayload +from .exc import BadSignature +from .signer import _make_keys_list +from .signer import Signer + +_t_str_bytes = _t.Union[str, bytes] +_t_opt_str_bytes = _t.Optional[_t_str_bytes] +_t_kwargs = _t.Dict[str, _t.Any] +_t_opt_kwargs = _t.Optional[_t_kwargs] +_t_signer = _t.Type[Signer] +_t_fallbacks = _t.List[_t.Union[_t_kwargs, _t.Tuple[_t_signer, _t_kwargs], _t_signer]] +_t_load_unsafe = _t.Tuple[bool, _t.Any] +_t_secret_key = _t.Union[_t.Iterable[_t_str_bytes], _t_str_bytes] + + +def is_text_serializer(serializer: _t.Any) -> bool: + """Checks whether a serializer generates text or binary.""" + return isinstance(serializer.dumps({}), str) + + +class Serializer: + """A serializer wraps a :class:`~itsdangerous.signer.Signer` to + enable serializing and securely signing data other than bytes. It + can unsign to verify that the data hasn't been changed. + + The serializer provides :meth:`dumps` and :meth:`loads`, similar to + :mod:`json`, and by default uses :mod:`json` internally to serialize + the data to bytes. + + The secret key should be a random string of ``bytes`` and should not + be saved to code or version control. Different salts should be used + to distinguish signing in different contexts. See :doc:`/concepts` + for information about the security of the secret key and salt. + + :param secret_key: The secret key to sign and verify with. Can be a + list of keys, oldest to newest, to support key rotation. + :param salt: Extra key to combine with ``secret_key`` to distinguish + signatures in different contexts. + :param serializer: An object that provides ``dumps`` and ``loads`` + methods for serializing data to a string. Defaults to + :attr:`default_serializer`, which defaults to :mod:`json`. + :param serializer_kwargs: Keyword arguments to pass when calling + ``serializer.dumps``. + :param signer: A ``Signer`` class to instantiate when signing data. + Defaults to :attr:`default_signer`, which defaults to + :class:`~itsdangerous.signer.Signer`. + :param signer_kwargs: Keyword arguments to pass when instantiating + the ``Signer`` class. + :param fallback_signers: List of signer parameters to try when + unsigning with the default signer fails. Each item can be a dict + of ``signer_kwargs``, a ``Signer`` class, or a tuple of + ``(signer, signer_kwargs)``. Defaults to + :attr:`default_fallback_signers`. + + .. versionchanged:: 2.0 + Added support for key rotation by passing a list to + ``secret_key``. + + .. versionchanged:: 2.0 + Removed the default SHA-512 fallback signer from + ``default_fallback_signers``. + + .. versionchanged:: 1.1 + Added support for ``fallback_signers`` and configured a default + SHA-512 fallback. This fallback is for users who used the yanked + 1.0.0 release which defaulted to SHA-512. + + .. versionchanged:: 0.14 + The ``signer`` and ``signer_kwargs`` parameters were added to + the constructor. + """ + + #: The default serialization module to use to serialize data to a + #: string internally. The default is :mod:`json`, but can be changed + #: to any object that provides ``dumps`` and ``loads`` methods. + default_serializer: _t.Any = json + + #: The default ``Signer`` class to instantiate when signing data. + #: The default is :class:`itsdangerous.signer.Signer`. + default_signer: _t_signer = Signer + + #: The default fallback signers to try when unsigning fails. + default_fallback_signers: _t_fallbacks = [] + + def __init__( + self, + secret_key: _t_secret_key, + salt: _t_opt_str_bytes = b"itsdangerous", + serializer: _t.Any = None, + serializer_kwargs: _t_opt_kwargs = None, + signer: _t.Optional[_t_signer] = None, + signer_kwargs: _t_opt_kwargs = None, + fallback_signers: _t.Optional[_t_fallbacks] = None, + ): + #: The list of secret keys to try for verifying signatures, from + #: oldest to newest. The newest (last) key is used for signing. + #: + #: This allows a key rotation system to keep a list of allowed + #: keys and remove expired ones. + self.secret_keys: _t.List[bytes] = _make_keys_list(secret_key) + + if salt is not None: + salt = want_bytes(salt) + # if salt is None then the signer's default is used + + self.salt = salt + + if serializer is None: + serializer = self.default_serializer + + self.serializer: _t.Any = serializer + self.is_text_serializer: bool = is_text_serializer(serializer) + + if signer is None: + signer = self.default_signer + + self.signer: _t_signer = signer + self.signer_kwargs: _t_kwargs = signer_kwargs or {} + + if fallback_signers is None: + fallback_signers = list(self.default_fallback_signers or ()) + + self.fallback_signers: _t_fallbacks = fallback_signers + self.serializer_kwargs: _t_kwargs = serializer_kwargs or {} + + @property + def secret_key(self) -> bytes: + """The newest (last) entry in the :attr:`secret_keys` list. This + is for compatibility from before key rotation support was added. + """ + return self.secret_keys[-1] + + def load_payload( + self, payload: bytes, serializer: _t.Optional[_t.Any] = None + ) -> _t.Any: + """Loads the encoded object. This function raises + :class:`.BadPayload` if the payload is not valid. The + ``serializer`` parameter can be used to override the serializer + stored on the class. The encoded ``payload`` should always be + bytes. + """ + if serializer is None: + serializer = self.serializer + is_text = self.is_text_serializer + else: + is_text = is_text_serializer(serializer) + + try: + if is_text: + return serializer.loads(payload.decode("utf-8")) + + return serializer.loads(payload) + except Exception as e: + raise BadPayload( + "Could not load the payload because an exception" + " occurred on unserializing the data.", + original_error=e, + ) from e + + def dump_payload(self, obj: _t.Any) -> bytes: + """Dumps the encoded object. The return value is always bytes. + If the internal serializer returns text, the value will be + encoded as UTF-8. + """ + return want_bytes(self.serializer.dumps(obj, **self.serializer_kwargs)) + + def make_signer(self, salt: _t_opt_str_bytes = None) -> Signer: + """Creates a new instance of the signer to be used. The default + implementation uses the :class:`.Signer` base class. + """ + if salt is None: + salt = self.salt + + return self.signer(self.secret_keys, salt=salt, **self.signer_kwargs) + + def iter_unsigners(self, salt: _t_opt_str_bytes = None) -> _t.Iterator[Signer]: + """Iterates over all signers to be tried for unsigning. Starts + with the configured signer, then constructs each signer + specified in ``fallback_signers``. + """ + if salt is None: + salt = self.salt + + yield self.make_signer(salt) + + for fallback in self.fallback_signers: + if isinstance(fallback, dict): + kwargs = fallback + fallback = self.signer + elif isinstance(fallback, tuple): + fallback, kwargs = fallback + else: + kwargs = self.signer_kwargs + + for secret_key in self.secret_keys: + yield fallback(secret_key, salt=salt, **kwargs) + + def dumps(self, obj: _t.Any, salt: _t_opt_str_bytes = None) -> _t_str_bytes: + """Returns a signed string serialized with the internal + serializer. The return value can be either a byte or unicode + string depending on the format of the internal serializer. + """ + payload = want_bytes(self.dump_payload(obj)) + rv = self.make_signer(salt).sign(payload) + + if self.is_text_serializer: + return rv.decode("utf-8") + + return rv + + def dump(self, obj: _t.Any, f: _t.IO, salt: _t_opt_str_bytes = None) -> None: + """Like :meth:`dumps` but dumps into a file. The file handle has + to be compatible with what the internal serializer expects. + """ + f.write(self.dumps(obj, salt)) + + def loads( + self, s: _t_str_bytes, salt: _t_opt_str_bytes = None, **kwargs: _t.Any + ) -> _t.Any: + """Reverse of :meth:`dumps`. Raises :exc:`.BadSignature` if the + signature validation fails. + """ + s = want_bytes(s) + last_exception = None + + for signer in self.iter_unsigners(salt): + try: + return self.load_payload(signer.unsign(s)) + except BadSignature as err: + last_exception = err + + raise _t.cast(BadSignature, last_exception) + + def load(self, f: _t.IO, salt: _t_opt_str_bytes = None) -> _t.Any: + """Like :meth:`loads` but loads from a file.""" + return self.loads(f.read(), salt) + + def loads_unsafe( + self, s: _t_str_bytes, salt: _t_opt_str_bytes = None + ) -> _t_load_unsafe: + """Like :meth:`loads` but without verifying the signature. This + is potentially very dangerous to use depending on how your + serializer works. The return value is ``(signature_valid, + payload)`` instead of just the payload. The first item will be a + boolean that indicates if the signature is valid. This function + never fails. + + Use it for debugging only and if you know that your serializer + module is not exploitable (for example, do not use it with a + pickle serializer). + + .. versionadded:: 0.15 + """ + return self._loads_unsafe_impl(s, salt) + + def _loads_unsafe_impl( + self, + s: _t_str_bytes, + salt: _t_opt_str_bytes, + load_kwargs: _t_opt_kwargs = None, + load_payload_kwargs: _t_opt_kwargs = None, + ) -> _t_load_unsafe: + """Low level helper function to implement :meth:`loads_unsafe` + in serializer subclasses. + """ + if load_kwargs is None: + load_kwargs = {} + + try: + return True, self.loads(s, salt=salt, **load_kwargs) + except BadSignature as e: + if e.payload is None: + return False, None + + if load_payload_kwargs is None: + load_payload_kwargs = {} + + try: + return ( + False, + self.load_payload(e.payload, **load_payload_kwargs), + ) + except BadPayload: + return False, None + + def load_unsafe(self, f: _t.IO, salt: _t_opt_str_bytes = None) -> _t_load_unsafe: + """Like :meth:`loads_unsafe` but loads from a file. + + .. versionadded:: 0.15 + """ + return self.loads_unsafe(f.read(), salt=salt) diff --git a/.venv/Lib/site-packages/itsdangerous/signer.py b/.venv/Lib/site-packages/itsdangerous/signer.py new file mode 100644 index 000000000..aa12005e9 --- /dev/null +++ b/.venv/Lib/site-packages/itsdangerous/signer.py @@ -0,0 +1,257 @@ +import hashlib +import hmac +import typing as _t + +from .encoding import _base64_alphabet +from .encoding import base64_decode +from .encoding import base64_encode +from .encoding import want_bytes +from .exc import BadSignature + +_t_str_bytes = _t.Union[str, bytes] +_t_opt_str_bytes = _t.Optional[_t_str_bytes] +_t_secret_key = _t.Union[_t.Iterable[_t_str_bytes], _t_str_bytes] + + +class SigningAlgorithm: + """Subclasses must implement :meth:`get_signature` to provide + signature generation functionality. + """ + + def get_signature(self, key: bytes, value: bytes) -> bytes: + """Returns the signature for the given key and value.""" + raise NotImplementedError() + + def verify_signature(self, key: bytes, value: bytes, sig: bytes) -> bool: + """Verifies the given signature matches the expected + signature. + """ + return hmac.compare_digest(sig, self.get_signature(key, value)) + + +class NoneAlgorithm(SigningAlgorithm): + """Provides an algorithm that does not perform any signing and + returns an empty signature. + """ + + def get_signature(self, key: bytes, value: bytes) -> bytes: + return b"" + + +class HMACAlgorithm(SigningAlgorithm): + """Provides signature generation using HMACs.""" + + #: The digest method to use with the MAC algorithm. This defaults to + #: SHA1, but can be changed to any other function in the hashlib + #: module. + default_digest_method: _t.Any = staticmethod(hashlib.sha1) + + def __init__(self, digest_method: _t.Any = None): + if digest_method is None: + digest_method = self.default_digest_method + + self.digest_method: _t.Any = digest_method + + def get_signature(self, key: bytes, value: bytes) -> bytes: + mac = hmac.new(key, msg=value, digestmod=self.digest_method) + return mac.digest() + + +def _make_keys_list(secret_key: _t_secret_key) -> _t.List[bytes]: + if isinstance(secret_key, (str, bytes)): + return [want_bytes(secret_key)] + + return [want_bytes(s) for s in secret_key] + + +class Signer: + """A signer securely signs bytes, then unsigns them to verify that + the value hasn't been changed. + + The secret key should be a random string of ``bytes`` and should not + be saved to code or version control. Different salts should be used + to distinguish signing in different contexts. See :doc:`/concepts` + for information about the security of the secret key and salt. + + :param secret_key: The secret key to sign and verify with. Can be a + list of keys, oldest to newest, to support key rotation. + :param salt: Extra key to combine with ``secret_key`` to distinguish + signatures in different contexts. + :param sep: Separator between the signature and value. + :param key_derivation: How to derive the signing key from the secret + key and salt. Possible values are ``concat``, ``django-concat``, + or ``hmac``. Defaults to :attr:`default_key_derivation`, which + defaults to ``django-concat``. + :param digest_method: Hash function to use when generating the HMAC + signature. Defaults to :attr:`default_digest_method`, which + defaults to :func:`hashlib.sha1`. Note that the security of the + hash alone doesn't apply when used intermediately in HMAC. + :param algorithm: A :class:`SigningAlgorithm` instance to use + instead of building a default :class:`HMACAlgorithm` with the + ``digest_method``. + + .. versionchanged:: 2.0 + Added support for key rotation by passing a list to + ``secret_key``. + + .. versionchanged:: 0.18 + ``algorithm`` was added as an argument to the class constructor. + + .. versionchanged:: 0.14 + ``key_derivation`` and ``digest_method`` were added as arguments + to the class constructor. + """ + + #: The default digest method to use for the signer. The default is + #: :func:`hashlib.sha1`, but can be changed to any :mod:`hashlib` or + #: compatible object. Note that the security of the hash alone + #: doesn't apply when used intermediately in HMAC. + #: + #: .. versionadded:: 0.14 + default_digest_method: _t.Any = staticmethod(hashlib.sha1) + + #: The default scheme to use to derive the signing key from the + #: secret key and salt. The default is ``django-concat``. Possible + #: values are ``concat``, ``django-concat``, and ``hmac``. + #: + #: .. versionadded:: 0.14 + default_key_derivation: str = "django-concat" + + def __init__( + self, + secret_key: _t_secret_key, + salt: _t_opt_str_bytes = b"itsdangerous.Signer", + sep: _t_str_bytes = b".", + key_derivation: _t.Optional[str] = None, + digest_method: _t.Optional[_t.Any] = None, + algorithm: _t.Optional[SigningAlgorithm] = None, + ): + #: The list of secret keys to try for verifying signatures, from + #: oldest to newest. The newest (last) key is used for signing. + #: + #: This allows a key rotation system to keep a list of allowed + #: keys and remove expired ones. + self.secret_keys: _t.List[bytes] = _make_keys_list(secret_key) + self.sep: bytes = want_bytes(sep) + + if self.sep in _base64_alphabet: + raise ValueError( + "The given separator cannot be used because it may be" + " contained in the signature itself. ASCII letters," + " digits, and '-_=' must not be used." + ) + + if salt is not None: + salt = want_bytes(salt) + else: + salt = b"itsdangerous.Signer" + + self.salt = salt + + if key_derivation is None: + key_derivation = self.default_key_derivation + + self.key_derivation: str = key_derivation + + if digest_method is None: + digest_method = self.default_digest_method + + self.digest_method: _t.Any = digest_method + + if algorithm is None: + algorithm = HMACAlgorithm(self.digest_method) + + self.algorithm: SigningAlgorithm = algorithm + + @property + def secret_key(self) -> bytes: + """The newest (last) entry in the :attr:`secret_keys` list. This + is for compatibility from before key rotation support was added. + """ + return self.secret_keys[-1] + + def derive_key(self, secret_key: _t_opt_str_bytes = None) -> bytes: + """This method is called to derive the key. The default key + derivation choices can be overridden here. Key derivation is not + intended to be used as a security method to make a complex key + out of a short password. Instead you should use large random + secret keys. + + :param secret_key: A specific secret key to derive from. + Defaults to the last item in :attr:`secret_keys`. + + .. versionchanged:: 2.0 + Added the ``secret_key`` parameter. + """ + if secret_key is None: + secret_key = self.secret_keys[-1] + else: + secret_key = want_bytes(secret_key) + + if self.key_derivation == "concat": + return _t.cast(bytes, self.digest_method(self.salt + secret_key).digest()) + elif self.key_derivation == "django-concat": + return _t.cast( + bytes, self.digest_method(self.salt + b"signer" + secret_key).digest() + ) + elif self.key_derivation == "hmac": + mac = hmac.new(secret_key, digestmod=self.digest_method) + mac.update(self.salt) + return mac.digest() + elif self.key_derivation == "none": + return secret_key + else: + raise TypeError("Unknown key derivation method") + + def get_signature(self, value: _t_str_bytes) -> bytes: + """Returns the signature for the given value.""" + value = want_bytes(value) + key = self.derive_key() + sig = self.algorithm.get_signature(key, value) + return base64_encode(sig) + + def sign(self, value: _t_str_bytes) -> bytes: + """Signs the given string.""" + value = want_bytes(value) + return value + self.sep + self.get_signature(value) + + def verify_signature(self, value: _t_str_bytes, sig: _t_str_bytes) -> bool: + """Verifies the signature for the given value.""" + try: + sig = base64_decode(sig) + except Exception: + return False + + value = want_bytes(value) + + for secret_key in reversed(self.secret_keys): + key = self.derive_key(secret_key) + + if self.algorithm.verify_signature(key, value, sig): + return True + + return False + + def unsign(self, signed_value: _t_str_bytes) -> bytes: + """Unsigns the given string.""" + signed_value = want_bytes(signed_value) + + if self.sep not in signed_value: + raise BadSignature(f"No {self.sep!r} found in value") + + value, sig = signed_value.rsplit(self.sep, 1) + + if self.verify_signature(value, sig): + return value + + raise BadSignature(f"Signature {sig!r} does not match", payload=value) + + def validate(self, signed_value: _t_str_bytes) -> bool: + """Only validates the given signed value. Returns ``True`` if + the signature exists and is valid. + """ + try: + self.unsign(signed_value) + return True + except BadSignature: + return False diff --git a/.venv/Lib/site-packages/itsdangerous/timed.py b/.venv/Lib/site-packages/itsdangerous/timed.py new file mode 100644 index 000000000..cad8da341 --- /dev/null +++ b/.venv/Lib/site-packages/itsdangerous/timed.py @@ -0,0 +1,234 @@ +import time +import typing +import typing as _t +from datetime import datetime +from datetime import timezone + +from .encoding import base64_decode +from .encoding import base64_encode +from .encoding import bytes_to_int +from .encoding import int_to_bytes +from .encoding import want_bytes +from .exc import BadSignature +from .exc import BadTimeSignature +from .exc import SignatureExpired +from .serializer import Serializer +from .signer import Signer + +_t_str_bytes = _t.Union[str, bytes] +_t_opt_str_bytes = _t.Optional[_t_str_bytes] +_t_opt_int = _t.Optional[int] + +if _t.TYPE_CHECKING: + import typing_extensions as _te + + +class TimestampSigner(Signer): + """Works like the regular :class:`.Signer` but also records the time + of the signing and can be used to expire signatures. The + :meth:`unsign` method can raise :exc:`.SignatureExpired` if the + unsigning failed because the signature is expired. + """ + + def get_timestamp(self) -> int: + """Returns the current timestamp. The function must return an + integer. + """ + return int(time.time()) + + def timestamp_to_datetime(self, ts: int) -> datetime: + """Convert the timestamp from :meth:`get_timestamp` into an + aware :class`datetime.datetime` in UTC. + + .. versionchanged:: 2.0 + The timestamp is returned as a timezone-aware ``datetime`` + in UTC rather than a naive ``datetime`` assumed to be UTC. + """ + return datetime.fromtimestamp(ts, tz=timezone.utc) + + def sign(self, value: _t_str_bytes) -> bytes: + """Signs the given string and also attaches time information.""" + value = want_bytes(value) + timestamp = base64_encode(int_to_bytes(self.get_timestamp())) + sep = want_bytes(self.sep) + value = value + sep + timestamp + return value + sep + self.get_signature(value) + + # Ignore overlapping signatures check, return_timestamp is the only + # parameter that affects the return type. + + @typing.overload + def unsign( # type: ignore + self, + signed_value: _t_str_bytes, + max_age: _t_opt_int = None, + return_timestamp: "_te.Literal[False]" = False, + ) -> bytes: + ... + + @typing.overload + def unsign( + self, + signed_value: _t_str_bytes, + max_age: _t_opt_int = None, + return_timestamp: "_te.Literal[True]" = True, + ) -> _t.Tuple[bytes, datetime]: + ... + + def unsign( + self, + signed_value: _t_str_bytes, + max_age: _t_opt_int = None, + return_timestamp: bool = False, + ) -> _t.Union[_t.Tuple[bytes, datetime], bytes]: + """Works like the regular :meth:`.Signer.unsign` but can also + validate the time. See the base docstring of the class for + the general behavior. If ``return_timestamp`` is ``True`` the + timestamp of the signature will be returned as an aware + :class:`datetime.datetime` object in UTC. + + .. versionchanged:: 2.0 + The timestamp is returned as a timezone-aware ``datetime`` + in UTC rather than a naive ``datetime`` assumed to be UTC. + """ + try: + result = super().unsign(signed_value) + sig_error = None + except BadSignature as e: + sig_error = e + result = e.payload or b"" + + sep = want_bytes(self.sep) + + # If there is no timestamp in the result there is something + # seriously wrong. In case there was a signature error, we raise + # that one directly, otherwise we have a weird situation in + # which we shouldn't have come except someone uses a time-based + # serializer on non-timestamp data, so catch that. + if sep not in result: + if sig_error: + raise sig_error + + raise BadTimeSignature("timestamp missing", payload=result) + + value, ts_bytes = result.rsplit(sep, 1) + ts_int: _t_opt_int = None + ts_dt: _t.Optional[datetime] = None + + try: + ts_int = bytes_to_int(base64_decode(ts_bytes)) + except Exception: + pass + + # Signature is *not* okay. Raise a proper error now that we have + # split the value and the timestamp. + if sig_error is not None: + if ts_int is not None: + try: + ts_dt = self.timestamp_to_datetime(ts_int) + except (ValueError, OSError, OverflowError) as exc: + # Windows raises OSError + # 32-bit raises OverflowError + raise BadTimeSignature( + "Malformed timestamp", payload=value + ) from exc + + raise BadTimeSignature(str(sig_error), payload=value, date_signed=ts_dt) + + # Signature was okay but the timestamp is actually not there or + # malformed. Should not happen, but we handle it anyway. + if ts_int is None: + raise BadTimeSignature("Malformed timestamp", payload=value) + + # Check timestamp is not older than max_age + if max_age is not None: + age = self.get_timestamp() - ts_int + + if age > max_age: + raise SignatureExpired( + f"Signature age {age} > {max_age} seconds", + payload=value, + date_signed=self.timestamp_to_datetime(ts_int), + ) + + if age < 0: + raise SignatureExpired( + f"Signature age {age} < 0 seconds", + payload=value, + date_signed=self.timestamp_to_datetime(ts_int), + ) + + if return_timestamp: + return value, self.timestamp_to_datetime(ts_int) + + return value + + def validate(self, signed_value: _t_str_bytes, max_age: _t_opt_int = None) -> bool: + """Only validates the given signed value. Returns ``True`` if + the signature exists and is valid.""" + try: + self.unsign(signed_value, max_age=max_age) + return True + except BadSignature: + return False + + +class TimedSerializer(Serializer): + """Uses :class:`TimestampSigner` instead of the default + :class:`.Signer`. + """ + + default_signer: _t.Type[TimestampSigner] = TimestampSigner + + def iter_unsigners( + self, salt: _t_opt_str_bytes = None + ) -> _t.Iterator[TimestampSigner]: + return _t.cast("_t.Iterator[TimestampSigner]", super().iter_unsigners(salt)) + + # TODO: Signature is incompatible because parameters were added + # before salt. + + def loads( # type: ignore + self, + s: _t_str_bytes, + max_age: _t_opt_int = None, + return_timestamp: bool = False, + salt: _t_opt_str_bytes = None, + ) -> _t.Any: + """Reverse of :meth:`dumps`, raises :exc:`.BadSignature` if the + signature validation fails. If a ``max_age`` is provided it will + ensure the signature is not older than that time in seconds. In + case the signature is outdated, :exc:`.SignatureExpired` is + raised. All arguments are forwarded to the signer's + :meth:`~TimestampSigner.unsign` method. + """ + s = want_bytes(s) + last_exception = None + + for signer in self.iter_unsigners(salt): + try: + base64d, timestamp = signer.unsign( + s, max_age=max_age, return_timestamp=True + ) + payload = self.load_payload(base64d) + + if return_timestamp: + return payload, timestamp + + return payload + except SignatureExpired: + # The signature was unsigned successfully but was + # expired. Do not try the next signer. + raise + except BadSignature as err: + last_exception = err + + raise _t.cast(BadSignature, last_exception) + + def loads_unsafe( # type: ignore + self, + s: _t_str_bytes, + max_age: _t_opt_int = None, + salt: _t_opt_str_bytes = None, + ) -> _t.Tuple[bool, _t.Any]: + return self._loads_unsafe_impl(s, salt, load_kwargs={"max_age": max_age}) diff --git a/.venv/Lib/site-packages/itsdangerous/url_safe.py b/.venv/Lib/site-packages/itsdangerous/url_safe.py new file mode 100644 index 000000000..d5a9b0c26 --- /dev/null +++ b/.venv/Lib/site-packages/itsdangerous/url_safe.py @@ -0,0 +1,80 @@ +import typing as _t +import zlib + +from ._json import _CompactJSON +from .encoding import base64_decode +from .encoding import base64_encode +from .exc import BadPayload +from .serializer import Serializer +from .timed import TimedSerializer + + +class URLSafeSerializerMixin(Serializer): + """Mixed in with a regular serializer it will attempt to zlib + compress the string to make it shorter if necessary. It will also + base64 encode the string so that it can safely be placed in a URL. + """ + + default_serializer = _CompactJSON + + def load_payload( + self, + payload: bytes, + *args: _t.Any, + serializer: _t.Optional[_t.Any] = None, + **kwargs: _t.Any, + ) -> _t.Any: + decompress = False + + if payload.startswith(b"."): + payload = payload[1:] + decompress = True + + try: + json = base64_decode(payload) + except Exception as e: + raise BadPayload( + "Could not base64 decode the payload because of an exception", + original_error=e, + ) from e + + if decompress: + try: + json = zlib.decompress(json) + except Exception as e: + raise BadPayload( + "Could not zlib decompress the payload before decoding the payload", + original_error=e, + ) from e + + return super().load_payload(json, *args, **kwargs) + + def dump_payload(self, obj: _t.Any) -> bytes: + json = super().dump_payload(obj) + is_compressed = False + compressed = zlib.compress(json) + + if len(compressed) < (len(json) - 1): + json = compressed + is_compressed = True + + base64d = base64_encode(json) + + if is_compressed: + base64d = b"." + base64d + + return base64d + + +class URLSafeSerializer(URLSafeSerializerMixin, Serializer): + """Works like :class:`.Serializer` but dumps and loads into a URL + safe string consisting of the upper and lowercase character of the + alphabet as well as ``'_'``, ``'-'`` and ``'.'``. + """ + + +class URLSafeTimedSerializer(URLSafeSerializerMixin, TimedSerializer): + """Works like :class:`.TimedSerializer` but dumps and loads into a + URL safe string consisting of the upper and lowercase character of + the alphabet as well as ``'_'``, ``'-'`` and ``'.'``. + """ diff --git a/.venv/Lib/site-packages/jinja2/__init__.py b/.venv/Lib/site-packages/jinja2/__init__.py new file mode 100644 index 000000000..e32392679 --- /dev/null +++ b/.venv/Lib/site-packages/jinja2/__init__.py @@ -0,0 +1,37 @@ +"""Jinja is a template engine written in pure Python. It provides a +non-XML syntax that supports inline expressions and an optional +sandboxed environment. +""" +from .bccache import BytecodeCache as BytecodeCache +from .bccache import FileSystemBytecodeCache as FileSystemBytecodeCache +from .bccache import MemcachedBytecodeCache as MemcachedBytecodeCache +from .environment import Environment as Environment +from .environment import Template as Template +from .exceptions import TemplateAssertionError as TemplateAssertionError +from .exceptions import TemplateError as TemplateError +from .exceptions import TemplateNotFound as TemplateNotFound +from .exceptions import TemplateRuntimeError as TemplateRuntimeError +from .exceptions import TemplatesNotFound as TemplatesNotFound +from .exceptions import TemplateSyntaxError as TemplateSyntaxError +from .exceptions import UndefinedError as UndefinedError +from .loaders import BaseLoader as BaseLoader +from .loaders import ChoiceLoader as ChoiceLoader +from .loaders import DictLoader as DictLoader +from .loaders import FileSystemLoader as FileSystemLoader +from .loaders import FunctionLoader as FunctionLoader +from .loaders import ModuleLoader as ModuleLoader +from .loaders import PackageLoader as PackageLoader +from .loaders import PrefixLoader as PrefixLoader +from .runtime import ChainableUndefined as ChainableUndefined +from .runtime import DebugUndefined as DebugUndefined +from .runtime import make_logging_undefined as make_logging_undefined +from .runtime import StrictUndefined as StrictUndefined +from .runtime import Undefined as Undefined +from .utils import clear_caches as clear_caches +from .utils import is_undefined as is_undefined +from .utils import pass_context as pass_context +from .utils import pass_environment as pass_environment +from .utils import pass_eval_context as pass_eval_context +from .utils import select_autoescape as select_autoescape + +__version__ = "3.1.2" diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/__init__.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f1f599fc1e17e7a84fb82084a4403ca13060515e GIT binary patch literal 2134 zcma)+O-~y~7{|vLu<;uX2#Uy zRQ1x2(B6Bf`fc{O@~Ki!y&>hssm}~q@FW~+KmO}C|9R$hAMc;#ask2T@{b?fUvmik zqZ;XFiKNrm7dCfDx3wS~EEbt;;)I0~g zgqJkW125xc%?tiYU|~!1BJe6+)w~3}hSxMN1Fz$C%`3on@Ey$-@LhZtcol!-t{tI` z^*6tN=dsts@`Ob!NrT8Il3J7!I;_ge0p>)V7KpgH4kXus5JNep5o5U+%QM} z#k->dH&cEp1m$W|JDi7HEuHqHMm05_g>pCSF&B~=srS6cq!-XMx0d>1D7l`RNBXkT z+{#Pl(jVcX+|(&-5<&Mv;!?Gd($-1nIXCUXw&%#}-s;VTTzi$>9&^-LuAS0B==S`Z zIm(B`IVHz8M(L2l9{Sea!4ZM&gk+k;%!(M$6zR2m;uG6pgz4z0k)l?|^kG$_!% zLv_&#o>%UK67{a*MI|LAWhE7mLC)7tPw+`)Rh86~Oev`=X(*Xi(gYdg_*DV%8D-5X znNu>aWC3I_){~wu_@XkFlq@S*QDP}s1sN1=`;2n+SF`QE&|9$3WoPTF&Pyn6(b*$i zuS+^%MA=c;;|}fY`b3RT__?`9{+(KvH>vn`EX)C%a7SVaFUKbDV z+qTC%Y1{4S{4)PI(53Z+w_q{#w-tNvqQA&yGMS5!Y-aQVDaoVECoy_790~d+HX}hh zu^EXu1coQ56`PTuz1WNdeHNRMpvSQp3EGa$NYInmj0A1QW+do~*o@ou^B_h>+?MlY zjEqRor?DA{ISI^p+ie&N>71`)WW;SVe|XQI$H<5T-HXjg(EZqq|K}Lf!YYY*aJYvL Qoxdy7KNr=P--C+!4`oS;O8@`> literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/_identifier.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/_identifier.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7eda7011d1559003c28892b27112680e90168a4a GIT binary patch literal 2150 zcmX|?O>84c6~~=KFf6M*a^u8pK{ZHRkPt#bNQeXCvLK`-Xvs_r%4{}?lFTAbw7)$` zdgD%J>^O;?j@w_|?M~b7_DABjEpY}8dzj2@mYrA5iMpiGaGDeULM*m^_5StVzpGw# z+v>(U?|eOi&l}@+%k_Ja$gP}w`C0g%czqwD5Lu2a&#gw@kIYA+kwHGu{;~5#oqf@MWwTe_t1;<$MtYI- z69j|w8bX6~6TzYLBBS#YG7cFT=VTa+stKxIAp}&NFskiSO+zS9twJ?}>M=(31l0qo zquNMPBSVcWHFhyksZpRtg&GDmCe(zpnV@DsO*qXsnHe&(WWs5xWNKu#$?TBXBMVL| zK~_K(oOX)r48jw#VYOAVD`XpFqbGYxEqGfAY6aAS*GZC-Aty@?td2@fo}2iuZk*gSLYCYe1eM$ZwG~F~B(+iQB&maPCrcfaJ1TXaQ72EG3Uv(XVzX|7x&d`z z^^)Yl>Sf7;)lx9@i^mgmB;sa{1~dl)e__C89zN>{PZb5?IQTRbihl8ywv3-kC%PM&kp%n ziR-(J>ng9LcqPp%Ca>y@S8ZNxBaC>nzU0V9G{7kwm9hsJudXL(07GyFrha@MG=*lsK98XgrOsJgfSJ>Iulh# z)G|!e4nHu zJ0@(K3ELHRPuP9oVrSP9ZcDh%U8{UIRM_2c|8A%wxOYSEZs^}#s_gD^|1Ow@xy(4s z?doAp?K2ElVGjRQ3<;0|X|N{~`(P-AwBS0s2I^tXuOjI;!rV9wG0ugWqA(0`0KXPX zgDFHDnRr`@t58cyPZF7ALkd6CQYip$$_ur$tfo;-dk`4~Jdt8A)Uqvz>;OzcZTAe5 zT`Sb~PFaiOXAfYBf24ummOsJp$D!>4BnQQ^smx?ZOJqQhLXys5lkl915ns*`c zJs?k1KtF|3PztppX(=LcY(pHQuhSC5sU2#%>{Q2Dwg09 zO!^u)lnESvB>Nck!@P~|^R^%6TT--;8Kar}coOC(`w)|Z@T6M;<*<~hF$^Yfr04>i zqJ*bZN~fgQ1(p;}Sb7qNc#;fDO+1)Vvk#=%Y=K@_vQV*3kg(3cxfE_#mcN^_k_K5R zjsQGm`4HrOv8Z?A8zEUhly|2Vq#@#4={9xQIHY)9F~(!&pz{t(?-e6+ImXz6?3{a|G| zy0*RY`<3YC{f$4p`PvUZT3>#=8vW7cTi8#&;kOuuaA9t4?nUG+<-gzXtC6?Ak^R=* dx5N3!SN{CXe=W?vJ^$|r2IZdoZsPqP`49Se2{8Zw literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/async_utils.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/async_utils.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ea30e9268b0915e5d370856d2ad1aab4a153e6da GIT binary patch literal 4651 zcmbss?{5^xb@q1mcJI#T^X~)Oq_#1nmj>Gy{|F8uJ_kc6)S}oi)EF)6+qHA%ymy)1 zGsYOnQJiu_sB%;g{s5AtQhJEA;v*m1s(-*n zDT!L+Z&NE|ao3oG+znLqg#6FIYODfB(hk09j4ZZmh?IG_cK!)S%6*bgIlR~VtHK(WGrdVOOiBjP#LbYoddV#T3s z7Dz2+pNGbql&lpM1OfqvE!s1hFCN2r>~ZwWHHL{4LX1giCKC}=fHU!U%;cl0AgVW& z$TJH2fI=n4)V3>pI5hpSDr0r}BXK4=BTmN?vN9e|;)pzbIwq>uk6e;xj)W75BNIt2 zj-z61x@%EZ7N^fgXQtJtCLc+Nk?Z1|tWM8Im3gtZ+ge0OYSEb5mAHwC^)L6@or@wc zP_(WSv3Nv`sVBQ6ITFVr@GW%}wn@aJwg6Z~Tfu$z7avQTr_!}g&KRA2nP9&W?AL4h zcVHOpE!asI`F{jk@{URo<7!|XVlgpqOzaxh0x*3blqilX3$mhFhsM?kEGgp#LiWE( zVjoOa-vaQOBnFMn;Y=`W1jBkw7!#ie(WX}r7UEJeCJO>YEI|<$NUKT^K23@-8zZp{ z!dG-ok)>x4i7=6~$t4q#sL4_UkYXX0`XhLEh(I4O4D%CXn1>nk3W}l?>IwBLh^%nrXTSYlHs@=cN zZ!~;WeZM*t-VU_o5an;n23t158zUPd_m|e0?LZCbJeCc%uP<-*>A~Lg002^JdbjJ} zT7Q3&(d)a@ZUCfKbz6Fy2>CII%_cvK;|oH3W*(D(V;PxAhn1VQk+E7b5tB_?l{HLa zfa#T@v$Hamm57WX1(Q#wz~^?rwj48os99;#Ral8Yf5qzL`}mg2(~0ey9;*` zro?hFkpw;nK;;2k0|B=U59bB!DLV3U+kX==xgykF@Qd%DfJxW481xVG=?Fz= zD_}KhJx%HSzOB~w-yZzt@bOH?kkK*pw~o=jc8uz$Co>(FjE+m0*2_lgW!TRvPj%{+ zerQ1V3}!rohG%dKI+pd$zLzt)C!Fzw4No}d@_2f3==;FGXyhHCfR;4g12#E^kT;>K z1F%KU(XFPp(_E&h$7t$Fo!LJ8PKq=5gV{h+s@gIY+f7`SDsUGOCJFf0+H6zzJH(H> zVTjyI>LCEcgk6W(U=Hm8E>NhdQD+*gHB1%~o1~1%R7ZRzHugEZJO2Q14p9{`wlXki zWNZ1dh;XAu{5)SumzYGsJfJMy-{VLt%M0d3&*oyI#|>6(&x>sI6uA^KtylRJw9+McVCj*vh{pvg)tl-RUSUFb7F; zr2%~9y5}7rs-wp8VbgSV^_bLBx!`xbCt^`m12;~bgzJkqB2>~<%1TQV6R@C4!mh0q z-PgTm-Jnw8@&QXuU$_HIh_aN62MC{1c4$_WFN{ZF^yh?vkl8Ci_EFUXEFVv$+0211 z<3JZ68DF=t=MES4_J8FB|{Jz%%hD?_a!n<2l$(&dpPAZG<14*$h89_kxBWm=_Vf^SIGEltVD`Qnfyn ypoyn~+3KMj4c~2ce~yJOp(zJVG}V*!4d!V0ZnN&S$<&8yS8^<1IrIi#3G_cNI54FE literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/bccache.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/bccache.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1f761a667ee73321c21a6d9bf909c0c49ccb78d4 GIT binary patch literal 20932 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 Q%FiCMobT4jXG`OM10i8~&;S4c literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/compiler.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/compiler.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3215140a03d20c5a8035107684066df88698af37 GIT binary patch literal 110493 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

    >goH)Z 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 H!E*c`#*eA~ literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/exceptions.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/exceptions.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e8a5179428ef5431b981470d0901eb4db533431e GIT binary patch literal 8620 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/filters.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/filters.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6afab1fb960943a3c4a2cc1a4c58ab93c63a6f6c GIT binary patch literal 75897 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%0D>qlNTx z+qWi}`Psg8$^2h#tV(A4nv?lI+eh11xj)C}F(8F61+g_#8?ZBFlw*%3lOn7cB@;c@ z4^5trmrvIw_Ro~RSC#0uR&P%Fw#@ssSiUV2y6r1gNj@`hePD^#@%#1i80398@#EqY zf*S2(PueZ*PH44W?PvgYd86ZnyHHwob3EQMy*AOB7)`8$axzSsItG*ZwP?juZMt@~X{)HgG8!ENG3+|IpvKS} zleJr6UO;c0y&z5@D67}~Hm=I-?~dK+ zw00k{HV-5#2CT?Y$BV}njG$w{b+ml27dw3mCr&!vW_`D#0oWyV;<1}smD{;dxjVX* z`&7@}@V)JKOT{PIW*(L27rn^QLd`r3?$tedQ_PEwtT)A#BX|x7-#O(&| zlsGq2o*0=vI&(USUR2rbXo#HadA}d^zIyL+^2Ff1D|g?po_JOw3c(Ys?V%%%w_V5f zCVy25@T#d)6dD6QvI+eb~$$7<`K)Nbs~~X@>Dse;R#*yMDci4 ztzFk_Z{F@icIdkt4M4^i+=WQ3V=&OqG6KYq98?kuYh~rja0JPuNb{FF#Z1NQ1h6rq zmR|077;-6HHY$#SLk&9C{s2-iTq&4=*vDAy1c+gWdb#4{QPjK2i7*v25#Scbkf-!= zeVb$sS2Bl-%p*-sfS9Tkv6X7YIMk}aDJG`ngLSGQ)0HXHx&J{ZB@&S$C0tcV(3NT= zk*HFG6A@IhQW?6nl9-PFrE+O1g}pVD8#wy$ebpPFs!C=1@j5q;eD>WJ8&|)DcLX6o6a0f6$OcYo;(J*;! zUazSg z!aWie_2}!#B-fL#z)4hyGjm>?LJ;Qb_5?^LCuKp}ajhPa1*6_Eh&Y-H-R>e`m8$-4 z%toTW+GKtAeEBY`eAh$?x|;OKwHs`3#l|&uU6Z|a=VIw$oihoc z^bjJr6Vovy97DQ#sy{wDb<_z+Ku{~Ka6*EHHP{#EkB#0u>O>@oLS{aP!6bG4MNb{;Uwg3O}$(wkg*R*@V4p$6^(-kQO{CA2WGfD{HPN{A^!h%rL}q@tPS zc^I-oafK~A?9#Hu&?>!|X`0g|H!qYlu;gY{^3p|WfN{8OuGo=BF*668NG21>$*nVk zQ5xlh*XQ**3u8N|rOSclRXs9<#cR=L!yac$juh z_vW(N8IWxl1{A5B!&>!fZl^>7Oql^v7CdPgm%*4lAu|vQ=k1lqgBTy!D{+c5&r43( z;us3iuEgHaSqgsj*2^96p0K`IDh+qpg#f})X{l;} zI0QacHAI}F{Q4OuLL97I0k*9g=L`W~$IGh2yd(4K+0v?C1dUa@fS5I2$cP(a-yODMW+?YAH(65GDx z_U^g!x3SFy-+~e0zOqUzPcTQd>S6G%)q0t{Lb|xr>;*oBO@uA)y*7J(ZtMFyXD>p} zQ38d}749)3Z>Uw~gI!H}x8wkFeC*y;u=Al zifkv|p&8-HE@v(Ab(#@D?bZ|TRQLwsk1_puXCv`VDtt5XEvoRX#J4GYJMkSV&z;1( z6y8mIm%<+>zFX1oG2%}sd=K%x3V)LLQ@U!_9-Thyze%I*7avqJ#CK49QY`_!2YF`puZu$kHg0o{R#15<3MORBR=e5$aCk!2Vq7^I4{1D mbjs(&cOf13g7~D$P!KM!w@X*sC99m5-C)K|1o%%hqy8H#8285j literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/idtracking.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/idtracking.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..167fe9d8fc063408ad860e1d5a1484efdba92cb8 GIT binary patch literal 19555 zcmd6Pe{369p5F{PLs8;Lq)7diEYbQ++15I?Y{zz-M6s;Ij-w>DoJ)01XjwzqbYxK( zQclcJJ!O&WDmkIi?)hrnML~I6UDj!Gt#QbqJ|HcOc3Uip{xKA|6+s|{fL?(fiWUmI z1-6U+(a-liayUa$itjE9bWDBc&3oVXX6F08@B6;L#y_jBt`czk=AT_r^?)G!SGvd_ z6}iHr8c`7L3aX%rGs1+Z+En|D?WTRgE($11Gty0YLPlAhaHx)n3bkUwsX8YrD+RS) ztqh4b*d1uBko|@$KX`M#AgEQqQSz6n%haN%u4#u_{ee7D%|@#+kMN!S+~`+h6P_1T z&j*6)`phN>U*L})6K>X0ixzK4{>+Xx{N>s_tj&kEx{|h9RlFz!8vce*$NmPC5dvaX zo{gxXCCi+eP7X+Zf)}!Jj)|*JxI=-ch`4 zh(EhQfm=k1fXrT0BSy&D@tWBRRu2+MjBqj<{B->0&C@3?Uy6pb=;aqCuZFKqUXIL# zW-mtOwW-kM(V5BUTL*q8boIdS+}wfjd5}0fIdggNR%rIt<@4dImvO7mfw{@4w1@u^TIXD4TF$3sD)F6M_Gg;8Jg zq7Edw!Zac7Pf#^LtO*)COQRF)ZVSLguHosg1yBVUn?x zvEZ2I#$Z`_CUh$_qYcs)TqWkB1E=j`D&n zVM_=>qc$Pp%2*s>0au3nVpqn!Vg^eH!e{9JMPUpfNMeT_ssNF0AJb?Mjrs;0S{s$w zOGsL1I*M0`OsY|cuTU)Oh(h*2-rKWMG&D2K&{zlS(sBla;n{F37>s*zB7HDl(}B^W z=K&UlZHJ)LE}hD_>zDpvrm1;FUXiz&+Sioi+o`60lv_HMq~)qiLmN)6Om9CzzsMTGS$c=ygd_KYA9RNd6Sblm)v@NZ4-}Buz68)A!~JK4}PoD{A@t>=GaWI0c9ncC=0jI z-5IwL!J){2dkP%(33x0aejk4vJAP63d`|>0)RUSgu=qUikD7Ar=@jDZ` zrysv$H$N}Q8O9=&E8QQuGcLF8YR&k&mqwP)t<0yCJsEf1lEUfZh=C_UF$+@=T^Ma* zC}1U8Xmd-@s?D@Yh{pN{3z%v3evA2P2W_HAJGsahN$bUpK|UfHUvHIckEU6~e#W?o zI3h~)&vVcdD93B_yC1N!Tl@6n# zAbRrXBZT%e01?T(GIZy-?rOu2=y7~?{LVAF(pf~Kz71dBJt^fokoFzWl>@V|ITF8KR^4{Y~-C;YL8tH`KL)$_4ofq41mRmOxc>@DAdka zI5K-i(;^xel5rl4^oAWu@Z+=zD|4V@FcTm&|7@X9L69Tcm|=Y@JDmxmUhiwAG4*trmUrcBSx` zeGPo{b>{Ezn0*cW1gthLYAUmi$kiL6saUom7@Q5g6AWf6gTW~n7f}?kXRF~U?Ackz z{G2)&3u(0CveHy!?lzZEdvTo?Oi!Y0S#r;!BCg~)gF3xNC^rGHrB(Yre)FR@S4Y;y zQq}v?)%(C4&Z=eCrn6#YOx~4lXZq{{g)ODxodee2isI1JmYxDeLmSD!}^fLYdE%8kJ*nxkF z)+y$lHV0$OTcS3FYlBPPf69Ed16LJ|No)UoKO}|0Px)t}b3%+6Iy!B{(>55mxPQTl z=eo!){mClI9jdTXf2PlnNy|3sfK#I>&e|tcl}$cZ??_5$q@QGKUK_p;Jpc0WNO1W4 z+2M;>uW@~8Y~;-7*|9St7V%LTnFkxu4sVqrGSedC)p>4Vmv7<@(KP@_5~s54`q=%E zdsRv~_oSVBbmtz32gS1zyK`H2`SBxZQMde_?(WUB`PW|DY&*EocJO{(s_kgH?dVEn z#@D9%`oSffN0Q@z+5WIuKlq|f{Bk~BcV4eMpQ&qE8HEm7UAw8YZ76N40l9}Vu(@aQD_{|?+G?4<Ofsh2EMjFphucEsqKVT^ z6JRq{n3-3GFATqQX8g@-y2tfJi$+&%+ z?v4$2M^gIb{-+;G`o1%|yCdZuO}j^R=jbkUqk$iP&s?N6gLPbbV9l81IrR1&)(r7H zr<$E@fSh0+gOx9wx%l$=*UprXi!G6Ygd;7DwxZ}T08=PFKK0S5)w-0cJ?(1OUA-B_ zQ{b!P4~F#qXBl4&rv=DYMO`IMAc^znD&)XjAxx&B z2q)GdQr-(Zhnjx4wInkiLYWnpl^wk*u!pU(g`1vG{UuWOmjla(*`0z5GDbC|VA7C( zKr)VmT)-%^dm1yeV{ZeaOmE{ZJN7m(ihD0#!TXn$wbmUQ^jo})cU*8RR3s{5)y9C3 z$<{I7Vw3=7o57LBPF=u<+;&)d(7Y^GofA~M^`6k~O#A!$gXXKp9NC$0zVD5Zk1Ka1 zoYQ2w8Pv?pWh7RY$Drpci}OBn3P>iWK)g13Ju*L|`e!3C|Mkf^cqRj`++G2*itiO< zeK0)%_FgP>6Apu!&@5kJq_t}!1jr5zRB{cIR7XCDgY&&c)(&&jX-xZ6a?4>VGCv#3 zDtt5HmRyv)8)R3rgZuNUbLd=qiPz^vnWdVX$I&SW5G>iQo+U@7p?h19Do--7G@5Dg zuN@$D6cqp~j*PE)b$so2v6-;_q%E_z?`JJPZMipke>k=GXnOC_2eqlaCsrIQw|-o+ zQnOt_J*$MePIRx_$H3BQNP^|FIazRV?e&z>n^t;tg(SrCxlLuyhO%dMYAu{n`qN6k zuJlv=i)Tg4fi44eJJB;+Ny89`^Hb+NDigy`_uLPctu~c4s#H{z7r{551EF(9vC)! zGwtYFdvCMj@J7es`y;82R~Sf8mvPg(r=wt_Fhx`ePi+nKjQgc8<- zg=dH(3}_sQBJ&CAo1KZWj)bkCw$Xk6{HcO^EWx`K(P9Wru+5aIJ;b?rhX$#<+`U8G zS?tbG=Woshxp%DK&M;N}A@#We0LJUs3;nluU`g7l@#;10-!!$a#@60THSJ3`foE*h zhZ$Irp!lw8D^IUHo$2WMrwf0waBrMX?#gp3u^+$i>n*b5mqxZ-g4>5-wrh4UpbV-% z#OZQ9NUaw*)X( zhQMZX^8{F^>>b}8DUBlhcpNy^^{qfkHv6ZpiCO2Rk8{-z8jX9W^-#O4q796<( zV8K-dgEu4U{0x7|S|eo+E32awcmJ&&ISayaW%&Nfg4%+J|RvGe;#n zzA=RI#^>i|LQF~0$oa%2`f(~fOW=6|=Lj%gpYvkq?RoM*XqQlzl}2DvYOhn#ei1vx z@1pd%zyt#m+U(I8AY(H+g5|tu{M&lz)opvV+`laVWEvXp+(u1>2R%P|JoX2G79JJfy-emoH3kWaw-hcb6c~*E>$4P=f!)uGrzJxr%irNT=h}ib7GQF^Er%1R~G1OmQUOp{_@=Y z+v)wo+XAj0s_aw@j=Jz#udcn8JbllXd?CFDTQF*hK?~}V!|P}6b*-N(ZnNU^od+Cc z9HcMM@#qTVS|J>#dJ$5SChQ2QNd;-6R)ib{XN_uCB?P@Fq~;7EypO*s{JHR_;IA5g zHTZM0F+BV>f>3shN{ms<@C;S0EM67xd<@S}*UI9#fLD(&AIGK8B|FsWP-7WY zrVfzJYTcNMwQY0Qi&=2J=mKXH(L3wHeS*2bdfq4e78=afE|YWdI#bxj2ub}*LTv(o zEN?w$$Xu9?2l9YBf>Fmel6-|ZK4Pbc(2^B21bR7i>BP4MyJxaFAHmEV*xyhE< z7WWu$|G7Qufu^kmr>=)*R2IRGYUFQY@u<&><55|e;T7pE)xl`^CImbuU%c5uA9K@R zVBoy1Ti?7{Kd@0hkgDIGuHO%jZsh<2OJ|_Erj@o$rE^2+Odd%ofwU6P*$>X&92Q@k zX2s2*;TUd0G_=^W-wUOrs}c2ffjSy_Yl=uw%Qz?qcX;^P>~k}bskh>L%;YF({x=xo z(J=t1boI@5{=xT1h?yKAk~o(hs`zD5Mho<>zZaPhT0mZlG&MOhgL6gb-Km**HKfhq z-sMQ;=Cn8sbWW(&QbHMx{}zKpM*$d_IOp6yt`qy5O4pzI9;xJHgFP8nwvf0@sS9btEKaHnJ`*JKt)!$04GQIW{3yja`p?` zaux}{o4^G^l$dwLfuh-bspPCU8qwnQr5uRr|A-FJ{|UhJE*e%FHh6^CEU|~yPdr&Mjq1I6^+bH1r!MXBZ+dz+JiW=- z`t6kGiL~bl-Sb37@h*-2H*dS%aX952N_&TNWoXM)3uUtMK&Gi3BBB~9ApmS*%NQxo z{^1)cwD|t^8uM~u!k9d;-(f)Sg1f}3I9L2mICeeWP|6lm|6i!vRRBomhL$@sB#z;P0KlZ1 zXZ5Jr5A}E7@3K-!dJgfj8-I_^0a(>QRWygkiJR_=?vA^LbD+) zJXKD8vNZiQ28hzMLC37wt9Oq7>+y%(e>L&-MEcY#xWX@0b17YONq1giJPY-WG+2}7 zj36DG{WkV=+8fkLF|&dJuhBGWK>||*VgT71&I02hyeWdZSr@-%+jjoqrO7ERlFjKq zqv07Sm6mq4vt^yU=h^9O2QRT|^~|lwnbQ$a@ZH!;5j8v=4ry7JNr}?lrN^i=)B$aQ zt`+m9sQn&Q*&(Gg6(wznE+yhl?GNaBg+Q19+cYVyj~N&Y{0m$~{}M}W(fEh;FCPOB zTY$qR4S)}g@>?)aa|0YLPOW$SjOA2_#y{QJ-SrSi|)3?7c#wvb*XDx zqA^41Ufc|&hfn9U6j6Rna=9T%F|AkuUf@$NuA=jrFafi z!MF;;GvYpF#-qG^%4el}li1pMJj!VGFg(f-+!>EDUA+v?w<{iH!qzdoLS}2Z_n-{f z28KuLg&k$zgED8E7+%30P;NZRsBK|*t-Fp_2fQ|hw`W&8%Dru8cpbaqQTDB$;qBcO zk8*H38D7_}cum0TW_Ufj;xz-WSC!$&Xw%5S5N{v$Gm(dlgEo&VEa86;-sCxC(_9%W z7S$F90T`G&IcOsxg~OcBYZ&v8?o8g#0;$w((OUY2f#JRQAJl{R6&rYCJ2GOGCH!OS zYLx2;KSU$jye!rQIbLWvJj$iT*rG18;ceI&dmlrQG1(Hu`ZM{1EaTd8mV|X&2~SdT zn3byU9M@iUT*GoO5B^=_G9Q*4KQufu<41B7+ySH_L@9@k+~`sNHA<$_BJ%$Yue-qGTBJRHS6&w745WNEcB_H`R@O#UZ0mLs~zt_02=b*mlAcYpsZz=;D%D}y$FOR2`BWdM`p8p|( zZ~67r#*J#fUhU7JvM6M1?Y7yM1CI_zZP=*p(5pLgs4S4FngW@KW#We%hZ+pn!C2C= zGz=CT!6Rd7e7AWf7F50xhM>HTUJQg3B({`j0vNeJ&!sdnO|BcYQMxhIWUeIVG@`MK z7m(Z7zB7HP{r^yJKL8dRl9ZH9XY+=$d9`~jkaBjXo!xr=SNgKViEO=iH$8!FopPIRe2oL8W@ITr%%@G)6$Y{ zsbWc(hEMwgg(th?u15NTm8c66CBviLnIE~RUCy=Vw`*ZeREsR=1&8_Rlcs0PkBLMC zDIq5u*NURH+`11q#`rf>%pg6*TM+C<&%7vEtii*E-o(ScrrW-yCP>*9Ndv7&rT0M1xMxNO!R5&Mn(?- z6pCKN&3_Fx^&i~yAKCC9N%@bZ{l|3W7=rcZR}XEq`k|RsBaHxHr6S{LS&{Bktsc`o z2k=Wy^D~EAt^24`##g^|mMd&w42~2KdRgYa;O|bRN7i{3=ELMw#0({By-I)#mn^&; z;pw3E`&2=}L8KdYQrTFR+CL{Wg*>%+>SPtxDQCIS6&xn{sKVz!j}mKM@n0dM_gNlN zyo;K6xg9fazx-e7_wNCI{c9qS(~C{Bilu`)`*det(gDDKnbwZArw{|!mMSV6K7D&F z{^vbk4x~GdAm~=v@F2iWj|03yQ`gFS$)WY*sm258#sf=Arm>S%oJcherW*%M6?)g< z``%RJP`YslwOq(_Za6!W=kM=-sOViUrJQ4F=a`=Vl}ei5u2^LO-+oX}TPHf2MX5$x z&n_aA*_rfBtyP5Pa)6JgoIPpwl?(s6rS!!N5qbspA>nD>F|1$e{5_QxV=s}o@yRw6 z_U6pjQu5|mCC6Mh=a51Y@7Q_8GK5;90e!PU?AJn(CL}@Y&H?|NPzLG3_*vd>0n%F(Pj6NZ8FgjMa0jk={ltn;qp->Js>#t+4M{_Y7oq zJoz{yl=QmDe6Y5${AX(96u{@lq>p8*@UbmYJCHnyZ;fLtVZoR&i;C5aPE02#Qn5UI z`bM?LO}K<;3cGfk!U9q~P2(bl+;tkakgI+U7IY=#1;EnCH*RPQe@9dKqgOGylrPzj%Zy(%U(uHm<*M^9rr@MBYs~LGXyMu0qs3JL7C?# zUtzp+$LBYkiUE2HTHL$u=fBl=$U3H(>$J>k{1LrI_l~b&a=Gp=_acwaz7lT4jEoT! zN}?N$lyi{89ZHWfnFdV-=Y%cmfR}eZ6lL62Dp6@wTO}%U-0otnl5_V5^sa}{6_bY0 z!&^{AD?1oqp@)ypeROVxl1kGouar_tkwd@{zArZ9qO9X0)+=9lw0f~_`SRqpe-t7t z$ED?^7xQrMGQC`AF^~G;!t@p-*W*twO&yzFGJEKIUM7i~N*b z+@=2=h3L2NSa8lEn34K*sefA%Wm>-$;1r%bwQaAIp&bEG=;9o^%p4rz=NHcYCz+L4 z=pv8EusLWD<({Ox?xK-rX~m&MgfYp+xOA?^`mx0|P z(nxbR$fc2@hTi}R9LgquI8#4zPVt|mpzxsfYYdOVLyV47F>qGMf#juh4_TCQ;9>30 zfsMj1fQ?fz@Y)d*Vnd_Ahem;h#;F)oNpk;cXe~^!n|{hYWrYXh>{JX8(CO!)DHM2U z3Iz&H;ZzJ9A|8WBy-?y&FBB;1g;OyAJvw+`2?ZW0LV*HHI28jHB76LRnke_>=cO+{ z@qK(=`sg{#08jn5LOz&_zKQZd9(_aM7kFx%b_7g1X>1{oN)_;C9f&7mPhm?u%a=a; zk0CTNw|Lh2c`A(%I78qI0?cc2g-Q(s=s%|6pXlL{C{{Saa3wHnj literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/lexer.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/lexer.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..66449f5119418afabbf89fd6127cd5d23fb0aaa6 GIT binary patch literal 35630 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 W&NEg6Rsv6lj~M>f&v0cd#s3T010DPT literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/loaders.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/loaders.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fa2f9ef5ce667af8ea0057a59585cf4112c9dc65 GIT binary patch literal 33088 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 A;s5{u literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/meta.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/meta.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cf25c7542271274684da3d8e5e5ed5d166755f47 GIT binary patch literal 5714 zcmcgwOKcm*8J;DV50RoJTQ6Hm;t6G0q9f6X;z!~{N?ciT9N9`5%T3G3rI*~Hw9;~y zon7i>2~`UNQ3@T@B87EG00C9p6m9_*aDW_IAcq`!Bn<)~7BCQ?2+-UZI01~D`p+!6 zBxN~3dg$zOc6MjxpZ_)A{}2Bh3I!09@Beg7?%$8lzu8Nrc*~6k*93%aA{oVyEXXcZ zh`D69EUNCb7!w5qZI9|ndt+YS_Cnhi^9hK!X8jdX)C;40YC}2@3kb-C&Li1>1IZ1< zd&`Z`ZTQ(G7L)@-oNcVU%R!(Ls=SeXhbm2!66MAlVyp>9H&;GF8)UExv=7v@TPp38 z7;6QZZI$;QKflUDtbGq|I~>Zc*@I5IhV$xtkRb#z9Fkp^QDon8d@QRaO-0uXY|cm~ zCW{%}AXw2-I!#Ng14{`#Yhsh6Gpb~g^0>4zJ!9eo2`HLLC^1Y$o5nB)W|~wtGK3S2 z2EJz8OneQ-L=nOAXu3=cXoNGFU`ODTEpkwB{5|vCK7Z`44V&<&K`tz4&_GKVI;U=ltXM2T%UJ=WfrsSnzk}`27H; zAxl`SGa54lHyT4H040H`ak=rFuJxLDfdaqLiNC-n%2uXqn;XpL7*hrTmWK~n?%JDc z-pS`M>TCR>t$bdJ?TI>0*e2kdd<%{L&3$fxG`Ahs62PHm9S5CtTxGkm-C&(+sdue& z=<2B{n7iuYwR=@uam&ISr$+l$#1%B_xaBMpj+c3Xc0v!^BD`!nfL-~*o-5*RJ~vKt z$Z{_qd5fe;IzcFwR25e}6xVoY)bar+>FPY0h%`_J=4^ukQpLGWEuXQJPUxy(c~o7J z;Q=;G8@50Drd2&5sRm^jZ@DE|j(Ba$G8DChxaE~Nx>=r#1QwzU^9?2+W@U{Vojw8Y z%TMoZ@)}MUS{uKC3Vijeim!Iv^LK5H=KbM83>3mAzX-o{FZ@zIJX8n| zm5{69G_UfFPpzMQ@7J5&El;tjZR^mzrf{w)yq&#su5beGi@9EQ7n@rP&Ch(%eEeSX z@jIS;^Ql7fsa*4^hb2#i4)?i;$aTO0j0Sc>=m!PB*Aln^|&O#awidA**~+ifKTkB?9A$B(MGjyR9t7a$|k zP}12;@WS>F-=7I+)PptLfSni#SH zngz&DlPJbNAxVh^L-?4~(-}pDxClL1F?$WH=_a1j^aTws%qYnjPN}+lWjUBGW0^oC zkXf<-nFU)dBbhV2K^93e%M%V$nggySlhY})(7#J22uawEuSAXp_{ibmVJ--^Lk3pT z8J(KACZFiXEQ~mVA>iPl+Wx+X(+AdtJ{S>&J#LV`-s?SFxhY+T?qQf`^9i^Reafk& zCS!^DEu@+t4!CZGR0<##1OtvzFzc6<`^M z6rQAb<`u{*IHW_Ieg<}!d{GR(d+E2AHoNm;dqHf^iS5PUfkH5n6C)fq>VSgbVmJIA{0=t$I1&IXR?s$l zc(j-`&`=Kt=g_8b^$3HHY6xF-nNDbhFzPaE!fQ1g-vXMq9lFNi56p1_cO4~Xjg+gN z7QM7ma|VMH;oPdbj=H;!j*}qlqH?5u&MdPeFD6Tk%4OG_h81^p+|STWK|mX?%0js{ zs)Z~829ss!+X!!9uf)uUH`xBeO2CirX+DGlQR!V?di~(f8wuCUjwmu~(IO1tZfbZ%lkcAB1 z3t zxVe-ehUKpaXaxYWHG`X%vg3&583Fe&Eze{Yc(cTdpd)&icg#y_me2@m`z|o=k%{Fo z?O{xn5DPfwi|h{w%Fc#XsIm@EZVk2oW6VCX*t-{AR(q;hYe?C&}I=)nFD_}>4r zeTW*Sm*ABh3XGFbm)wFNlw2-B1Z_d(MM6ss9kA~&5wz>>BI?f7-$m4wtG~Z=i#M20 z2$7=Lm#e=^-ev(#kdIbiNcQ#HYS+;=;n?=c9q>$O+>!2*Pe<;~@|WG!v#6-l^j*YZXo_~x3w;<3!3(S7D|MSj&jeLH%aO$Te1m7N8akc&z^4X*E literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/nativetypes.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/nativetypes.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3bdd987c3174b00f0e512474608d15f30d0ce665 GIT binary patch literal 7976 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/runtime.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/runtime.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3bb88d7916112f84c5a71ea58f105a7c521a8f08 GIT binary patch literal 50661 zcmd7533Oc7c_#R3MFCYn0VwPniv);;1i@8Yz)cW$iGnSYk}XIIP(&3-kRSlPDsU-* zGAt`Lq{GCpn~GqEN-Euy8?u-&lU6e9ZcQfk*g2k_lb$N3CakFmrAGNeQuQRjqX$RXa&A*Xn|hTM3&COqf8LtY2{xF<@^`-XhN?3pM%Up7=G%wCxN zLw;c{fjKY~fY}!ds61aaR3*#-n5&1Xg}EH&&`?O2D<*2r z*ACSRb8w>WeEm?pFjvCdFw`K-RWLUWH41Yz%uPd0!W@FRd8k>KYhZ2}Y7ypIm|KTh z9g0(lxzD!g6%wuczC%&o#lL)pRu#C{!*^JBjW*zGwf;5cY}Ad)&BpIL5fA?5GqeUi z+x0JXwW!sOp$_q0JJg99YMSUe-#ygL934@j&95ramRRT69zD$WU5F3=@)=rpT8Xy) zQ^(MHyxZ{ZjjoEViiTsW#@x}>ueygeM44ir?%$eEGneqc5&qlZf79pi-vR%dOBMMS zJr?bZc1639!WJX7jg~Ze;Ih?p!B<%Simp5D!1p%&J7x)Itxc;ry55#jVcaXWh9x(> zu}7jC3S!u9rVp1-i=nR|^p4LJIvia$RvF#+s%L1YXy;96=gkFuWmj}dYz^9G4ccZa z>bgJXJ!_uYT=ofcQARL0%6Ew?l9{T;z60xE+Dp(IPka9yt;_i2pO7(JJf7Tr z@=PqO&P*o8&&R@JGn1o<@u|spI5HUx#}ko6EIbpBMZ>2qhexN*PmfQ)oQR#Do`6fd z?=M-p!5&B66*)DEmuK`$WPB0^Z!A6SeB-O~q?X9wRO0Z|%w!aHHM-rGWNr_s>J&p(JUtnWjg3#nqPmU$ z(1pmvfvL$v>=GmM4Sz8bj}NG)VfKzrO^!xr8yJVXIvJT5or*H2CFjTE@$pG|DjkfR zkHx1WqqMJ_I(0TSnix)8o{kNxv1uk*HH`>|V@PEf@iCdasCFZeo8dp?_x?|p`Css1% zi+a&be9;m#VQIeN_|(+&mtv>|^)MPxkqOPkk;wawq0S8Gp-VN>lT4skgLpSpm3TTX$_J<+%33 zvWHe)W!1*z5}JHUO}+G1rc_id`}F`KQ~{7lGu57oyq{H}b@F_bF*agjF|_q)EbnW*HU9}sl=>$T=~j@ z_~pq_OX4b#G1X7sj!SA7?@@Lm{VC{Dv*=Pij^yz#iOv@fk0&tMsHbN*O8Ua+LSr)% z;jt+-JQ`CIm`%coGZ>WcM^mhfoekYaA6I?CLbMB-nk!12>4jzca1~Yw4$?vE9zG>d zK6g}9C0aK2qAjx}@F@E~qIpv}tz2;=EQLuJ*pH&jD)trOigVU^PXw8)RlrZwX%C%ZQx-i5HnsN5I%b{r80|5PIvr??t3!#P z9s;Fu*!`ffT*>|DW|%Z%lMyZsXopB5EN6JM%UF0aHX4h^BkEu6VN|OCdfe(R zTDwlojOBft(;}Ebu;!?zjrm8mH?cL9;0gT4zX~v?+%F5v9k>^)eq-n2iA->HHn@83 zXf9a4thhY81ekZ_eEx5hy-FcwgB zu){FCsn|Lf?X@St(rZs)M=NR|M{?_lajeNP4kSyxW65Sy#Mx$C&+%!tVqcF-)ULW0 z$*9DtF@RXl)&WE$S0#9c4h;Zv3d;9J`x~Q+Tfe>G+J=ljob`v(?yxB7;k@56Hq|Eh z&zI}yf|!2u-cu7(qvzuJ5_BoCZn`f-)Og+-KNC@7=m@7LrcOmBU;%GMr=T`zo>5CVizW z10D%!&-d{*QBVx@(DNANSA17WXG^WEHRDh{v!$~ov%WnDakXYvNm<%ekB!p@{9u62 zdTzSDkD>goF`O~v+{v}aH0&gNCN?o0Q{|K>>nuE~#>7bM8`Nh$c6hGQ(ecql-h(l6 zJ}&0_d^sAO^*lU^ML6D5rXGS%m7PyLLU4@WaRNr69tX&Kr_mN%_s+#G=RH7jW@2&9 z@tk|*BZgbvKN-8I<3H+2cz6!~aaIym;Tpvkn48T7tLELgl5&o;4Y{h?dGEaU=T)@} zrx(trs?$}y_@xr^J?|C%N<1A{9Rt-Icx&#}HZFF4`}u3n&mYb;g@3d6d%fT7yWY2~ zI7>SOc=oO%6QOA%gS_Z_+4bDMH%tK`CtkFF|*ZAP#gRKWt zK`G3oQ4gBZuWmxj$p)g?BSfJ_#8PJ9(D@Rrh18?)Czj8_QS0(SvzRfs9;4SgW|d)> z~=^&*tGGBmn4l$nsu0{?Gt@%D$ zq|`odXb9{F`=)b$oSmwWJI$DWTJ;g22rIQmJV zsNG0J)(gx2jziRgWm0F8lZ<&-lS{W(5H{WefKmqs-q^P2=K7Znb*6&@_$}4kY|HlS zkspM<0a0$O)$C%HzKkhHj3g4!^6?3QDov-T5;u3*VEoLFnL)e60ODv+6h?i za&6}*5<}?{4DkfOobi`)uSvVtEV~_^)tEMH!0YtvPq{eK_b)kadW4}6_#B?c9E)7) z@&05eGsL{){hVuu&&LvHrlPhb-e~S?@b*nKxOG`FoAas2+W`mEp=an&V zC|?cOmmy%MmXTu;jtNfJ+5?OZUC89yq1$){<=`-899#a~2pGcugM9#RINk*J?lp|b z6uycddw%R)*_@h6Fq(!z!Rgb`8AKEp)6kq8kDf6)Csz$yDwQ^Udn6vPuTOaRCc`xY zd<4WU*fjsr;>c=-msaayeSP6XKQoL*Q0KdRWSAKQ-8><(d&iI?N{^qp1S>%5dNf=LsW_qAv1~B;r zT#&#sSQT|e-QWti&l+7J=EYZu9^S@kq>E2?iFwUQ7)x4V3fwg^ECd6&_r@|g&q+_iivn8VbsDk=xMjh8- zQ=&fBaMp0NPbEW*ntPMpiwfMEGb?!; zRf0(x7Ry=WuQ2+E#Q|v${7=$TM6JVTrY52wyWj*`W}M8Ucz9|o95H|AnKBILYu#U&{biwZUh`LX9gSdiBST0S9)Gc^+@BN&W1 zmWhQl^S~lVmVjUvpP8DOU?K?-+o_lyIl0GY;G?fhIGjWrdetGDIv+kAnmZrpl0da^%E?PZq>;GDP(N24 zW*Gcot&k%~D7atxT=|SxdM5E(OTy!>e)EGN$B-~Gws(%DSWoqI=Y(zvR zu`HAvoiaKVi%)hX!ef!~iSR{qafBIpB6e9Y|3|{7W)dhT8QW|x5xQT{zWpNxD{~|) zdHRB=*4X~$*p*{yP*TdAZ`7v#P>}}_Cl%PusFb21)t=! zUWT57Kaz7|>iEQOWzFbbxvFI>o zAklsD0gb&i%rT^XfkBS|^mrvcF5+6Dv&Gr0pk47uV(3|XCo2m}_RnA&C%FptOQllZ z3PRnV>t2UfX>Q#k^X{y#;a)>~>R`5G+pTD(VRyD+H{8na_4K||d$X4AO}Ux|;eBmy zYWS@K-#v8w(Bh&0s{Quqf7$zfFFiD3Tcf@o)v?t1!`>hCzSDQJ4)_Ol}^3 zqK?4Um{G|^5*&?poazh6m--06C`XF^uwY{3{4X%PiJdVU?Qi7~fW?EKZtOLAh>~M-}KnW<*4&n z^yQ1nCD*gcMTd2Sahx*;g}jR%Z?f)7VlOTn!P?In3JaEKpUP48F=ux<6HZRq+{0Xz zvCe$#=*xRBqsLT`_MDT@dDw@*^}`O|C9y4p4OcN6iq4rY#rCP(9~F(za(HtyP*wtLK||Gdv0w@SMHI& zKimO!T}>a@bu|@W*VQ19v)l??i0Gq_KKg}Esca)3W~uYm+Dvd~Hn=nG+ZpGOd}YHX z<<`1^R@aYO9DwSVV3#jJWkhBs61INGmKXhSCk(P5S~*lF6!aaq=nwji2YttBZ+~oS zWw0-HE<7`h#?^5_Vn0OSdc(lJ|-p(Uk<0ymewwVc?}x2DSo_<*tK(^prWsm6L#zX@QQ zcJnUa5J|t@UGVWo^ujTZ&QjqjZAN1+x~}a?2U^e*um$5NZ8kwJ)HFZHKklM5qhaIR zg?y!?OnE)f=vs6%y5#g>ES_*>lZj>{Q;4j_6yC*8;ieY1>a1INGm6@5<+P<3XVEk3 zxLLG0HcKH2XJinw&u46T;Iu{Ph|%sETJq3FF+3g{3tyg^0g8_qftXAOK#;xwpc5_K~EZ|R}5~aYDWbq1|jgsWKi#y zn#COijqe8#dlePccgs8Oly{^~WXgN8gV^)@3qcQx3;E38#19C+0c%3 zV8?xIZj?%PjkQzKEIQ>G7$n2~EKKsbfX(=at#KzL@7q|(G{45TeMYjbW$1*C&(jIR zBO`j#kA&k`gCIRKVYKh3cfT)aUCY{K3i_e!Ge&o`%u06rzE?;11py)`Ijx^s2?&y{ zA~7SAdOtllMPh)9qb)Phamc?UK*mYBh%?#epFq*I1dbtC*;QC1 zn+m#^rO*Ba18_r7^tM27q2pRl8tgtl=frEf7EfH;mkzAH@2`Nv`n10lKRWDQjAM07 z2ikugtkX7JY*@3=)z%?uvYG{(*zv0GHOr<;Au7%pE4ls%XwnEKkc*NQ6oeF4A{}cr z)|YsnElHvXf;-#`1G&QjRj<6_n0377H2b-=uL5ze(hzs-F|$Tdu`_t77YI54w1s3& zqPLvQlihl4qGJr}xmpQ%|34UhH2`?B=^*wb_)85eI2N{{W}mvI*}zg_?+%swS!$HQ zIJQP43p!v;Ct0&n>c3!+FaT1zucw4~muj*-yYbEh_he!1lL-}7n{`sKv`@SQ6M`|w zF$q|{gc}l+&k4oK?zj3A``nf|x#P`AA^ESRoDIeX`3@8kfJon{#<&9KK`;WwCr2k{ zqL9=O-t@XQhMJCP#6h(m1`;zh4Pn9Yq{cb`Qz1@?LAiR2pFSh_Gdg~uk>DJE;C?{V z3W-l&4ui2p{t)nAGNVN2o1yR>m{R6UVH+tAN&ReCb7t<eL0Gm=F*K+YNG? zSaZc3Qo!lNq+t;ZBJ){rJdGJfk60&%j0{08EW9F1bxJh?Tiq?GjF=P2Ng=&C2+2=i zCDVc*llKn`vRiy4j|e_y_##p>h-FMrqYt&BCF@{!E}V8|Ykixl7xBUfGbXT%B5bqc2mr zIa|3oUAgyuP2;t}`9nVsHD^N|si!lc_1Vz+dEb41=#5L+`mVH}KS=jf)_p7adUCNh z6YR{`W__J$U+1#h3;su_Vd0U* zj&!Ieg(!OX3-o}xZCO^_5LcWFpP`Tu5 z#H-O-KWQyFxK{be+Kxj3*H8TpKp~=KTXi@$aSeFz*8p~D11pLEGtouy5NBJN$o)Rt z-_?9U<`nA{h-b{8?;5ixh-bxIJ!YLIXL{CYZb7fSN<>}YA1fALMyy7XFxc}@h`!oq zHF9Bq=(v;rvPfV~JIg@2L2hx?9=<48a-0_9 zm*d!75o9;FDu_MnxRjJn4#&ZaF=i%XCq`^sFdcB>DDVo3%Q8FJIpJK0x8h%jUpxWE zCHWdJG?=__8$waQ{2X&WqrB;GC|4V;l40(NafmyRfn{UZd|bMRyI_~5)qTk|`Xr#$ zkOk4!{q%Ecpy3&FpwQyW?@#W?G-f0{WiF`kqMpp2(S$nK8VO37W;A z?1Z712{7#=gV@CSFBo!sPLt#W*SrIv1((-KZSvFtyPe!jGf5Sz?Eq_oo8gq-3N0kA zT}}tX>EI5qNe|w9BHghg?b}hzx?qk)u18?_Tk+F^HcF*{Z}tk%8$q2+Kb&bMagmXc z=Ux~Ai{dg$dr5LoxdewJ#uyth_x>PRY2~J_$jx-AB-JGg={1=2o<@p3?-m=Ftbnk- z(?WT)WJn(z7M8?8R`6!HVxa^Fy5?@M^G>ic70(3MXM^kK-S_>$H+IbLpWlD4x=G4P zrvt0*2SeKah>bYpEGVjd0*22kAh_~b1N$7x{R?zArXe1DyWisBAxMIaz($P#B;DNM zS5LtRF}_h+cN2(lDn@J+pB70%A*W~EhLWO#UtrB_hgWvJCvBpGPo{%UF4g?7Q`dY4YzTK(SIrJ-!g&TQ2# zGjWjv3DyNXyK*?MMKRogN#`K0`*)@*~xBI1KSL@SNec95D z%O3b$R_vgq%mdCpz(QQSQcvA@S{QCc-irxCA!rDCsu#B|D|n?g-`KIV`Q{_H)~DC+ z&9?6omW5zVrKdhMx~$-}6uF5wVJHM0PS4)O$n~+*iKW#y*QSQDZJQ_>y0;McN9iMXtW#T5{P%)4KIH*GkjwJ?}pvOrmlYs;<>8 z`qNeIS%|WG;B#5g0VM>hUwvN0wEPuE88Z%moSt2(x>&G(w&aA(44v2AUx*Sr=*Ux3j*JaDs%^l9c50=T3*M~BJ?rflY z?hxf@ccwx>wmmzSYQ(D$cuPGsi)cE$QZL?^5r#rg=kN?_QniCZs`lYfE<_j*#-mf# z5AMUtF7k*YlAxM}$fM`1R}T^MoHcOCs2k#n9+S?GSvV695k&LGN~0xFpAb8A50%CI zl<+?r&|{C5nY;~%hWU#`;mTtb6rhA#pvWy~xIygDJ}*N|(1%&LLTtNSE!#Q7|k`f6qdO|?p6r1h>oY8cUZmzt#d$H=Z{cnw?I&Q4bwDo1%`tJDq(*8cOWA|o5 zy>~;~?}WDJDhFIBy9R-{J5SQjwKQQ{5o2|Fq@B9Do3A+x;FVa!=_^;Zy``X?;l8l!-xQJ}4sY;bqx z+Yq1Hu9F#RJN$ya5W6tq*epAlHZ~zYMS@YvPxTcv@^FO5f5mxh3yo;_pJem*Auf$b z3>;3c^joZ&f6D6cz>Ofk>gN61L z29u1zyCzkN4k#uxBto+>N!dC&9mQks==LwsnRSnfx%!&xE;@6_@Bp5+Jv?{2^%Ejx z=FEc=zH!-n>K`F+VQ*kZP&tz2!SN#G=Ye%x_V(Da_wxYC)Et3 z`Rwh`&8hV2z1cdPY}>zFN>A8N3oZL;3Mge2%jGlyIkkcY#aprL^m?9gEWCK_VtUn{ zY&|e)ep?}t+=^GfB0WM{k(jd&xIIvOyi8yq!?djt-bz6U;II~6CNR9&Y-PQ$Hb(Jp zJbume;28`!6S;gEYbuU-I&r+yHRQ1#?u_}&;Q>U^y$2D*%7$=Gz(f&Y@6qhb3+%m` zJx-h0{Fi9Uw+d%2cv9ry@mC_2T0MSi%JPKE_u=%e?yL;e#pzu^t;KL_C~|8RZf(d{@%fci$d{!>;HL>W3>zVui(*?X+`MPG z(u&6#J{qtR7l;k#ObSZa{<*^AG)h7Ej%Zt~3c0RA8>~WJ*FvR|r37$kgA0{qQGwMO zyt_mhyI0JwQjlLN&FYD*`@}x69`Sb+<*OH|tVfC0B8Cl77jTqrbtBSD#s_yU8E`*QJK$@3eZgdNYJOic6o~9;YPK1Uj3G6gbk&5A;dCm7SY!FnFwVi_G(66uoEDIg%X_^6>4o-V3qd@8fTLrv}|-1*KPhkPyveQEG1=K=ix&>h3g?GF5+O~ z5wsa&lwXwPcN<@%&5SiXDiFfRqe#MFiE4sQdWHAn@R3&a*a~5Dn0pVJS7Xz&e+B8p zu#i{eHVSt`*?QPBfbh_yJT)X}I)G_42Dw8>3nJa~+QB5cX-PmFi!~{wP<07HMhX#V zaPS4aBHH)VRP-{pTugm0dJ4jsB8u|Fjf@c+sYS(+?Syhe8B&ajWw50qVq^@IGBJWu zKunK*um^`mhxJ+mlO5Wr#1}b;ngfkx!$x(XhiT_vY<6P*f0tGT=< zYmOs7CU03Dw*NL4?p<&O0oA57tpT-Lk!x(d+qmvdss(-3gFvlVWWeF5pUrZVIf*3d9Mz^4X2PfOJk+|?&3SyV9UCtrv5pzUjZ-B6oQS1 zqp!Vu_2sm$wU{nrhZcio8$#F-UWm9@DBTlS2|pXHj)8$l@acpeIO zEXc4G6}Hy_QQMU_Fjp9~#!$57u>jdcTE>b@x*gv>J#PtP6<3rQLDgH!@vJiG)(;ri zYX#C>-#acQJpE*z-ghlRkH_SWi0&efSZQb9D9VK&Ha69Z+*IMoDzRw-31aIOOME;D z>Gg34c*MgooCH*HI*^hJ*dN8f!VrewRXBnj)1+l6;@tlqqlD@o5d0}XzVsy26UcK3 zZ__eIz|N$;O7L$9NH6GQo#=NKvJ^UDL}`=N*1jk0-es@*4FnbpBT!#^(*Aa`81`V- zW!dd1ecExaxot6V{pCz^U$(h#{@~T)^T)AI-@u~?PXjeI;k|mYOb0Xd>$COi=a1%E zSKn>zyVKgYbScxiGuyfoVFwx6rSI;&zISQc&HhaDBe!ebZ~o&W>0Ku>%_n8t^T(G< z7$D!0(MPWiz=`(u@^9|s+Pwvmc*$WcL`_EDh|OAhtV;Z`UMN3{y5 z3utu+S*u60`~%hxnW|zt@ajuxUsLgjWL=99Syz;{}6>U(MNsn@=m_O<;@%dz2r%%Ma~h)n3iXackHidlXK`UAx&n@vTzW*4^S zT6p{;;G{!l?$tQ_cL%lna>fp@zQ&=dmM<-V$phn4OPi9l*48qt|2vc+&H;@U3s4U8C9%s8q&&?(WOZ!*+g1k|%7q;u@6*d|U)6Qn zKUt|Vo`YCZ+SmOFmC=Bt?0qBZI496VF%~y{`3w%r3har}CGu>rJWOo#5o@pL6R58G zzphjOj|gY)!@}x+V%Do6=&QHZ(<6e2)8}sR_W6jhgz`2+r$Md zOj2toyX35Okt|#oBYx!BBKa&3*4Tu=1u5La0i!R8LaLx2q9>7l<4}Zw6OI=zpRr44 zAQp&~uP^)soD&aE$71JjHXd6yi1BD6Ol5mEn0!PoppeRio#4%!Ftm2q7qQaUha9ZQE1Ph6?)$9gjcOipDIPB*e z%WK|Ek8<@b9MfgPEX^=IB!fG z;v^bSi@*#f^b3R|7pBIAA_**#A{H|gX5t5^6)Cq;*lKQ;Gg)bEFWUS^wiKB^n13rV zZol=_*T0$xhO@!&+t8M_KJ8myJbpQL#rQo6gMIv}wLppyW$^Qn`pZr_&)?azkx zrvv*T+H;jC-Y3-QSwzG-P2pYq*tJa+4*4j_>YB>Ln%QCV=NBJr0*1D&V_tA54 zC(&&w>!;6%)k;P6w}xLI&Xl)h%iHXy2xX7y&xCeoL%Y*~-R4G+5a6~UhaTjC1mgn= z5~0sH;x@IFg)I(&I-5A5Z8a?zok<5Jygp=(7Ap9f=3ri^J5 z!n#O^hy6q{mT}&M;muY6(u+WPc0?92(ElCEqYBK76laenI!VcRTU&ZW>~<_iSXHtW zx5B%It#Y9E->Ys;x9rSR@5)x=pwKRiaqb7b-JXj6R?m%|ObtZ+degpMG3M112yAOa z4pz~K-0HDUrn8Q7oMsiZlnrNcEy&IjI)_}z|5|I5k&%eNAdF(OVFB1>j_ zojeQ*FM~4bZNd7nwMB`>g|$Jwz?Q1PrRhJy5C;N`|t+FsQxEdNQ6-gu>YQ)VmU3IDxqavprM5oDQ(xW zQNN7fs7UOc?lw?IDAsJAf9zh*;JUd;F! zXvoz!U%LXlGLUO%!mAuwW*4^2Uz!ifeqgCmg#{G-K!w3R2IqoSj$NU8ZA__33So*L zG1VH@Xig(NX!1o`=9MOxT;0i^05hG`u}~m2JeCg*Iw^=Ssg7PN2V5|}H9cEoLl^_u z;I3fk8)tRp^gKQZO;$1ip5bDgmce|IqZ2WOh2|{5+2ep688KqS)FL?QQpd2sTQRC} z;Om?@m=I5{xIh0T;ZhuZ5QHhIDuiO$-@5YpmBp{55;v~gKKTCQ z^H(y#BiZ1QwC_mql)(Wmy2_Ve_`FisW+#B!R=cbx1dwK?q7U;f3F==zHg+iO_dYlwW-wNn(BuGi7er_4KVM zt00EGVCPc!TKypbr4;hP;o-<6bVtauz|iR$qLY|8PSa#g67zZ3jEfk5#e(Dc^?|AOEng8xkL{}3pc z>s4sGhnAd^GdKgSdTCKjC$7!%fL@HIc7iT~wFIma0ltm^@!RMgbC$nlr;`HP1h~AR za_;c`Rqb;}=AXJcwCK7zoOZY4mvOh}YMSQ`&ktNZ1nr*qW!%lVy4Ja)^O38uw7V6* zjJq{g+af|fop!h2mvOh`R(Ge}^^iNRO}k<0&bYh5M%(;IuC9LBU*lU9*9O5xWfnd3;=)ed>i?&kFhQ-a4q}h@VHE&Ig@mP z?pVhj1dWwIB;951=fQ03GR7=|1Mw#DAZ{wQuNEOf_=0Ntg4k+=o4p2%@X<1B`4GNX zc)m6oq}cpWok*F>gLqIAW-NuWD%9ZH5Ul`)RjF==cZr_fp(zYtqr)(3%Y~gTpK147 zWdo}B04!93*sDyo7G8hTXO$Cpg3B@26&ykY`q8x5oe8#QaW#Rjy%^ze!{68O|6m{b zo_^BPBo6*gcEKl#cEO>GQmApX9OC^X31+buZnOh(YdkCLg|kHBv0~Q6{!Fn`Z7-at zmkd{_n?C1W_}`UGwE81tz=n$c7#7L(MXfG3%T^MBewKZJXoV&MUB5HE(l0fz=&(Ad z{|$ollosroOC&i5r7L6eCl=GrLkL z|9{v&|4w7Ca&w^bv0B%UYaD>Kv5peTF|`SX;xT2F%`e_%Ro5Vp`d0)|0PEN%&Y5f~ zs#kq`Zxdy=#4QoB(eG0&VwxvzZ9gcN>CZsTjHX%U?>guI+e$enqMU4eXwIoh;4@`> zcP7}E_Vsq2`V@Dqf< zj}bS8ZcN_~7poDS0Fqq)7V$`OhNBMxV4!paYa?Gx%^adak5RCWeDtFJLV6_GTvY4k zKH6#4`(^l&9mdWMq3SQF-B@ZyhJaX$-G7hrctNsqKW~(R8rz_uF0R;O4Y%v&8ux zK`>jn*vZ7Y%hl&^TCTr~4VppqW8^@kl)m~?0Nc7l>UD*2tM58oV2!Y0v>K5+QkhT( zRIjAV3xA(=C&E@wz)B?EcpfpDUW?W|R?ve&Xc1dqk!mlX8}dRn<=<+St)JH(4dhp8irt=jFN%>TD!p<2{XqY$WoH^5vFEb4nFgv8ZJ% zJ1*4L7&j(|$l{qo*(OVf(}3g)nT#O8{`q}6a1xQ6AKaD=Wt#+|e%t9_a(0+aK{*^{ zy}b=@R?bci=jp!+_Qy;%xHj$PFXLW&-&3{hba^^*V7hdHvR#*Y>iPy8$zFB4iu(VW zc4w>iEW6-=C%jiJR%M~y)`L$77iz$uUTIM#Xna3te4JCq%LE32PTMBo&Ee^jN3wD1 z9A*IwZ?uq%6NhIbZ#%-v1Qu@_mvM5tnfwG2`Cv}i0S>U^=#Im)W$_?`Z!v)-jxAbJ zUYyo(+$iC#N=q-LyRkCu<^dn@8FXL-qDAFHI0PX1>rscb=}nKNdmhWKK2XRVurmu} z3$pP>@ozjNx%fPI6b)&T@!AzRAS?^7$l-M$R>Bmgx4q)Z8iN$EUUCyH#le{}{QL1A zuwJfWJsN~tu*-3*2B*hk0bDO)y?%z5%#_P4LaP#vo#3YDszO5AzKG(28eXAe=Eo9) z$vlWw^GJ_~kC)2?KW7*o$*C0Kol#yMQzbSZ>($N3YqI{!yf!Hu0bd_C$r@K);MT!I zaF*9Qx+%&pkEQ2Jbv17Bd;oWNjGh^mIudaSq4@bzcjyQ9P(=)|Q29mV{#gKhs6{8yB=L*rQ9dH%b@KRhrJd(@) zECM7e#C^qv3V`o$TK*m!u+LMcw04Wz2cT^p`+a5iR;@|x`tHluU#4Y?erG|WJSx$m zd2PkT2fWcho{Pw>>RQ^BUWJ1b2yveZcGp4$`JzAD(3c5r%my)Ey2|(D)^57HcK4mN zyKf)NtR2X%#cA|4_}yQ-DZ6$z4ejC@g>c%(pPY-{U}=9%6dAyVK$XFQNcMvvbU7eU z4t1;b=sC23T5dS7;x~3lN43H3)7)#~UBkFFPWff0IU`(gpxapXi?6tBhaMbJbX=3M zW({fYsL)($%vk8q1%v7ev|L{Ca>$r*X(A2hU}p@RPm05yZ(OPRde|PO<1xDw9A48UM}xL6@nXw#Y}!OSv3erDzVP; zt_kROj|!b1Nv~YYlV1_qPRA!NO!4+ADN=B8N{SCj2`h>T#HVAU<5b!#W75|VN+mc_agvCaRoE2AhLg31V?xS(K{euJI2kZ>%XY_m zdg}9KwEyT2X)YAt2^)bJJbHoTtmzCinrrSyMF8C8!xB3cHoz7*oke% za%`CbEVx1VRCVN9*8Jw<-+Mfj$Y4XcrFY@b!l94u)nkv=Q3WDL2lraq>9TMLET^gt zu$=BA&pV-7AsuSZwRbHX&s8?wtqk9(45w-{m0j7&uC(|q2bo+ov@vFzH{$q|5V!?R z;VxafI4fSc+U7ThzB82aEp=pSH)d-$;?9|1?flEAplsv1yN%oKG;T{ja`b1H(v90P zjbF(&eg%qQ1GRSpEq9>e>X}TS15#t@KnED#SwHBlGU#tz!5Kbs<=CF~!5KKh_H=MH ze)sBDfi|i=;J_)CXHi<1tPuKK>#L#9wH^eJtEw8iKcSXf<(C(0t~aJDzl`5cYknI2 z+4dhz{A40Ca3VW!LfRI}tWaf6){hNP>XtR~b~4qGU9&yCW+#5x)?JxEe>Tvc7QcJt zl?yemJ$v=p#hPs6hC4!|EyQ7{V|F_eXS-|{;9gDrqWgM9rlu=f)5W%t*1`?Br|1j- z@t_LSJw#__U!Pq(mP%%VTe86|Y2OyHvGwDc+Q-&8f4r{hv3;H&?{xr*u{mm>*cb>j ze;xl1jsr+ej?g@UFZs+meia@}H95dzoX{3xi37772GhIvmk(shajabOW}Rvm?4=4A zw;ZYh+Z3bpSKvSH1|WVZHT#!q>R{yPPKGo@Ga?k(NX!45gKrl`PllOxBhMiO1QtLW~bXDeDJA!BNV) zQtpP<-U+Qujo)g@g!W`ZIDfh4etG@;Nyx-Brpw!nx@);tRln%`cGI;caGK1ERFIhQ zaM>1Br@~;bx;b16J{hug7>ih?z3W^7ifp3~3+OCUuagknasax;?b@C}khGIilb6rq zK!G}fOb9)hy5JUSn4RaT6h_3?Du#`%}# zU;4e1w>#eN`JLhShUeY6;3k_e*QRuE(^3t9_VaC$)W;gc(oW7HVnuU620; z{5K9YiSOp27V&N!f;tu0uY%GSzE=;e5%2b)4)I*)$aAl_A_6DI)yq=lfPS6r#c^ESBraA!z;HkA zQn1|ADlc{IFB5Xm`}Xa_(T}O{Uh~jWH!r{2+XdUM9>Wi|3%g+>ExNi4dwHwgl=$YE z3d4bst`Be9qPb}ICxp8NaRUKnaU2s!yEx|1(=WV*!+m{HK3bee+R|rS0uk>s4zh{t z_lHIPNG%!lCZc%94c44th3gt76S&{OwBThkRu3#|zQ*FgNOCam7NK3dZ9=R|F1V>- z^b4D!8cY##MJ0tqh7|aTFv-WxQTDAJ*hUT$6)rY z=YqHn*$_hA;SR~yYg^5Cb8Z#%oRH7g(Z%=bwD^hX(8g_ZBRt|!9()X7M;8iD8-tcd z?&OnTIPJl0FJ*9JEaCx&!|@hQMc6oK7WafPYeE$#D)(Jhuz2Ea1=PQho*g*>vO#5` zmK5Itp7t5T7HRcnSR6U{%40L*xQQE#d)yZdg&kp2g_6;`B&Bbh;=(277jcGwOaZNX z^TH@uzt2WS*_df;_h+W3KI+CC<(6)PAu5_SFPyB zz1EYfYs%KGOXDP-`~`OZJlMF{k!|YxJy#~UEgKZHcg4>`;=}w zIZ&xBn@B~;Z|wV(SNsBM4#FhBx9TxC%7I}3imaHvhp;!Ie z1vMFD3>nog`;mE41lz!S*|G-!aL}Uz*);E`iL)dIUDhZ;MC73qI^d?l6f4( zwNgmX);1h_5rwR@7Lqn+SU#dWbBeg4?X~39&_+rJEENZvUfl>{jJvqff+ry4OmpFyT=ORlt=WVX3g!pg0BqhlfQ?RD4I zJycs4szY`PugJ4hJ2$A3h+X+eCDaiC4@25j)@Bt}FEVNF5TV9E`K!e>v_fj)sM3l_ ziQ_@`WP~Cl)}@h5<@}4q$*|+J#uykhS`C0WD^&*UVZKh+#)57?%L^1Gzxe{2~1hOP1zPoYxgv3A(AV0l~Ujp)>M& zjKa<+?OtYv^d9k9&hzU1k5tl%=?UhAy;&shC;5(kAcpYe&QL|i}D z#{D|URuL=|fxMiiou4hi-BQU``8PCi0hA0DF~L89PwMExRn5GU4N*!H$H~ko%}SbJ zb$$jlC45N}tfJ!=G%IPs0+9d_BR>L&&-OKjGoPw-D~Frqld(_fd5|VpO;4ee%->|} zH2e!r&@Z7FoSi42Rz|#en;gDRYu~5&jUb>~U_fOdl?aW*K9Rrr3Is*$_Nr82Hp z;WrNZ1+PAnuIa{2(J}&E8?uZ_#3z9~?-lZtr6AaZmkG#a5+~wlyAB*D>OvlH9l1<8WDMdgl(4E4QMf&uDFB8SnNPxC0wVyN!C>2X%#n5< zojU?Be+FQ&KD9H~ceL1U_3pHL_uLZ;y}90IlMw0j2*HolbWek|>NZ0<0?{4)RxV~ZCwJEZp5{P^N}GXmZ>(jyPd!H|k#8sZT= zJMcO@ow}b+>8F!^tN?!6$VIcAPn4fZz!l1@1O2D1ggsZPrI-FQ0N zgiBxWT?o8R!RuRv_;JuPccPFg|yy@ zsnbxvn5^I%+Bo`-i*H;#1Z^BPEY3hO@)#H2RKDqcQ+Z99I}B+N$AogliTxPo$~3SY z&3GN5QW#amkBGso+gmAN^LURvF8deOR#$>Es`fxm!ZGF+7g&2<4ZQAlDo2!gemkSy zSA9{4LfH@3%N>m#Uxdi|5viyIC*4^+VX#5uO{CztsIkP13Qc+Py1p4h$B?Gg_6(FQ zkp(5FUIY)1LaP&QRtuBrn1P-x@Vt&mFN|G3$WPsS;B!fy7aIb;#y|<{(J&WCTvMQ8 zu+y~s!9`w42pwG_#Gy+O-p$;vak@xoXP}uB+l#i*`HeD|ksLFrJ=Qv-m6i_kDN~`z)K!dp z={09aE=DHC6PKZ~1X-Z`LUAfuE`%DIe$hcJyhu$kqLj7Bdqhu?EH$Qfy%BX1ZQUPU8wWL6f@`Sx zDG6?;dWDN*5SI8|Gm)tMA|9nz|l2{|M+hu0gGM9UIf@m!8gU zIE2mXQeJvdie=3PB(7*JEy)Hx4}JsS4JYrak10dIX@@W&QR_ZLT{&fm2OAdFFL%^4 z=ABpOonk5o3_&a^Rx;*X-C9ChS>{>@A3~HNgx`px6gGi*C{h_J z2f1GM@up9!pyLJOO=2W(Aor#ypvo%(ZG0RSa25U^EC9UWu*pMlE(ji6y-tBC)P#5tup^OYC}*`#kE1}o zfN4j9)K?G(k;eFcfWME>U-iFSP2GIyvb&_TA=lV+y>{6}lf0@Cru*eh%O1QT`u0hn z+6lol?C0b4DZu9}?bNPstj)GT)EwWR0z?pyLZ9w)1uvrh)n7sBdwls4qEtW-@}&j> zDH;aXX+@()fy44B1}>XdW0CXvrwbQd=e_X+E@n^#;ekCq&g1G!1iwna*yY^9Rc!=w z`=b)os9Sk7sn-zTm)RKqrPdhBy^615?&X}XZoYzl_p8<{)Mu;KyuCA11${NW^Io7E zcYTd_e2wX*jf-8`rj5Vndao>lb5>2eGrm1p-=4H@56;MX%HBH0Ggf6wpt10JI4G+l z!T70QaoY#<^r7i<6R*;AYsx*5f8)^!pa*hm#*WkQCZU)II0`g(0BiA36eFrYNB|l+ zh9FDMh=0DiN_{z+iwJ$In)J+t#|Ihqn{w8K#W)1iPy*#b0@wyTY}|n~N(HyX0pQ=Q02N2}chpX0q(77q-22`Re7guR)IX=h0nk3;=vv zIraq_5TApyjamEzERt<2rf%#*{V6hF9^M_q$)AE5o(Pzn=0yovB9#%#`;goDX>#p; zjSd7qV!2ow`t%GG&RI^b9YLE?6#~}|Orl1~D4|HJ#|pqhso_M7S9%*(PMC_NEQ~zZ1@F*Y_!m?D{nb*wrRVS zYA%r7;OP|fCHcT_7=oXr`Zx7Im=u*A2N!~$mayV}bPu*%JhK!B^$NL)lEGx7Ao_Wj zLKC0Rny^2dtb!Cod}j2FE(*~f{@C%{$Bq}0F0@Y46~1x>YiK{ae1RN9Ei#Br^A5c7 zC7PszZDbNVO4ivs1?B{?mG&PwbiRh5z{M%l4v_~6wbvcJ)sfwDI9+!XzxgBcNA8zb zWy`7eyL>%fQ%Y|G+#0SlqHH9$@Rf|V%6<#-PXWNIz~%}bxd246Hpo|xsH@YI|t>;xOZSI z%&ivihT>pJlDCFyOvIYbgE!Eze0gd{$md0;c(splCxJNd19=}QLMAU8;Np)955^N+ zywpW%VxJKx0cWof&1xjfd=yPu1;zgKS?i?w_a$dXY{f47_xG9dKag;t7-WMz!H17W zv1=xXFhLxPk@*+s{89iy?92%|QS8k9fDY{h=C~zyLM8am9JgPDqdsc6fLC$c5_F1j zn``gQwqx_>$Q(A9j?7J6MF{ zc}sa^Z8c3o+KoaMDrb3>lJ@x$YCe4?q6$5zQa=AQ9UJIae)8Eb9vVJy^w5DPjtw3W zlvch<7I7HLhhmdtxySQPlNTR(zeeBzV?dX|_*go}l5duFY{s9^Z3y{N+QwGw? zKu)Pl>%W{*HYfgaN_ATQ<&@^M{a0*rUujL-e>wXnTyx5*wEcHqX;0gKIr}GEb4qvG z{>v%7Y5Omybf)dUoYI!I|BCaRQySCuUvUm|N>keY%PB2s`){Q@ccc~D@4mZyZs65p z^P^uIe06Znk<&k+inb|rfVw(Tk7pY&1fukHuiI`g-#RwExg_tP2L5%Zd)>e9K{XH7s;6SFv2-c9bt* zYn-o$col*QpQC=^scS>fSmJ@oD4gwc)GuunuR>7gbgW)jO|81upUzhEP=;gm61LRw zDg@O^@1|U+A-8i+4o6;sO%Cs}0+6d}TXx}nKU9M=WTV&iFMH_ZRmv-_9$whG=(t{% zI+ogf%kf^>?XB+x)9w4S4UeWnk7fe{%O&*bQ~ZIe>yY1P77ySYN$uj}+1jpbS@&`& zUCWg6s%1Y-0m>l^EjqFd-Af_d*c@AG$~J7vmOrvwPUi|H_&9E1zMKlBA~#~Grfhw0 zHn2hF6!HSWns6}dN(+*yTDMuE*Wy9S-dGuM9sB_8(eZPr1<3ezt4b zwTqPtkPDPweLP*?l??zt=l71C?_Ib(p51X&eBSqXUwvl&7|t>+d-Nb8oCKE~4GySq zE(VK@AJFzg(`kFF1EZxFEIj)GZ9g=f9(B|^b}lQ$U}5|N+J0y{^(&qV=(f(e>(cHp SrVJ>&&bdQU7dD_+_5VMF!1>_- literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/sandbox.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/sandbox.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a05173b375cc4ced43ea5e8474ea48dad3db3673 GIT binary patch literal 18833 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/tests.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/tests.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3fd8f1ac33c5013cd828ed524c5a4e199a5b5bbf GIT binary patch literal 9256 zcmc&(U2Ggja-P|p{$J zo#k?OxjY*IGTf=Io~rJy>Z-1;ZvI1KV^qQO>UYal>v2W-532Z2xPZJouPMr>ilrY^&jz+w<(FsY?Niy@V0TCy$`UJL^dS#`-ss(!Iv;NfI6r7!BL!h&lJe)qf% zT#;mBs%fzaT=lHkin5kf&C);77F$c|4XC$?dSij7&T7K9Bls3vJL>mWXx$7-dsRvc zD94y?wOZ8Malv0_9r;B299?|nccUzJRPY?F;OVS7LOVw2s!BNqN_SPtaZpZFrF4MO zQsk!sx`ve07uyoz%kYiIL?j% zzQ#HLCs-$7jCBFN&bk5LU?%`4Sr6c8)(d!sodi6~48U`&5AZze2Yiza{94607uXMADr|qz#v) z){~~ofH}I!@bRn<>iF4ylmL(jGL~_W8YHObEB#kG*{v%>gF=36~@0+ z@fp?n>uHOvCeqA8rDff8oF$gNm*93f#nLXm>9c!PFLcjLW|&vUnVaG1IQ8K_0U$xV zFDZ_Esysp%+o)3%D{zM>3RDPg4E#*AGhCiwMq*XSd(Y$vb0vwoW7w7z`w2;fWQ zOO@9HacCUl)s2~{o7Wx2otqz+D~T2JCUi{C+Zi5bH?Jm5=g!2Rvz3W=*ViW&GSEC> zCU3^>L7AIBNvzy-5-yuqH{*BATgHQ{|p$YbRj zy=8Oq$y;0MuP*1b&X@S6d~dA>57C-I$QY+^&V}xcgpmwVZ{7^ls}~XyE2jxQLOiVm z+K3uVXHs!7Ku_&#eqlGad*)(C7&%-m-2J7fpbD7Au>xR-DeWRjH!AfapcOKeZJ z(SWcDZ^sx84P+Qn#ug!CvH8jaj-62HAT|BRmh#im90 zsp6J6*dxU)QSfu%Ulr>Ouf8w^qrlt(x7Lr8dheI?u z`=&-N6=UcZqCGLuBUXiB@9|C<4OL+;fYq%2@Y#E7sXP#BEZ+vX})a&&1vkieZBZ zOL3ep1H2a#CnJ7oSkZ;OBp2@o%Ne|dh?4JB8d^7Jp8YtdpUi0|rLz^|0{93o4TRM! z^znWR(QrmB`v`{rOY0=w1AqtUcU_9b24<8hRd_z3StYhmhwVa?##r=!{dk zzl^sK#q&{`Qqn;m+nU|JzBQNA#%d^2F|k)_Dsk1s{&%?O2S^?zCsSekauf}WB4|wm`Qvv;J4{)3 zMzy6&sUqjTR#QFrQX=iLTS)MV+sVP+gv_rC5_v(isn}MfQx$sSbn1D4*BJpoY5=D? zhHZ8Jh2FQL_vQ4tZT9uq+^IK#{nPBfwCASbWpkBgE6&6Z$Q7>E*4$W4+NOKB+P=~u z!C#?v!6T_JP8-w5q%@`IdrDt_p%3in137J=Qb97aF!dE6<);1|8`D>K<+EMH{4Z4Q zzjF~u(pVM6{ajCOAqezw6UWBbXuu01s(RssBf|dy>Pgz0817eiUy>70qSTblJehhr z_3wJm@AaM+`pKP=O}JFp{|_a_Hs~wK&p~2RQhYr?NlCj1&cDXXFA$(eUHyde103>H z6}yy1cNij(z6G0zRVHMv5LG5al9OM8bkFea%Ut~>ruEg3{ybWhdt2%GYK`_y@$5fo z3ICcuM30oYz79o<5i5a>i@EXGXpLodUM7M;sWiEY7yc93LxuJ-#uWPJ?|}C=c%5Sa zd&_P9`OjbIqdWR&P8+Q;1wX)mBUKbHU0B7#vTs5Sf>kIXO(>7m{5^2|mUJjReEiu9 zeQ-w~%xQx)v!LMm#Incn^YrvT}St7$E+Oo*dmT`NK zzLjLIofbm*d4K6yKqNhIb-JVDACN65YWTN7g-9hN;XeZ5ABm%os~x2r^PpUf98~Oy z)aq~-7fxM_SBg@@sV9pTO1Q(0v2Hu^q6_8`?ups6k^aCO1^dO|rvXnRqF2B0V4cl! zZu0|t)Aw*b2f6e-9e-kx=f2SJ3>YGtN#wicy zmRb?I0~@`?2_RF;dn?$TIdO9x>3|nmTDt9~l1oc;Fu!d&jCS zMF2^p`E^kKji{vuhnehjPCH(Z7B|73MwhLgUUHr3g$ws`UVZWQ$g7hV6P`xBdm5by zy>Q`Z<%Prw1Pw<3q#rWV=BF{X7ZN#@7ZO>AS0{ILFI?E$ygIo*co9F~c@f{eyht4D zl|m_+iRI;m3&!vQiS$O`(j_mz?&9O!jG1)pjX)nhq}eO=vKP4JdipIacsMi#9(-UM zfym6 zUAg_gZQL0&3UhOkP2;bww2AAW9tbl4GHq zNbU0AII$)AII$fkjuT&4q9_N^CiS%~^?4|-0NEZCMLFmXs3Ti_&xfe($hHt^MBpVL zss!5dfhN`1{7Y(Xd~rq;U!N7l9{BGd7bTSk2l!LCY-ysm{5JfpS8cetIuA@2Z4Q~MYGrPAz(;GLv6Vu1NksjB1)(!`zT*ecvK0sZ1(1L!W)!OWA;wI zk?|xJwo_VCDf2z%(oMMO!6EjyhHMI65b_wx(Poa@gBl^C4Q1{ zLyp@=c)x5rK)6C+P!fj-Kc$44HyiWAgpWvkl<+aaBl&T{Uz7Y3gvVrOuM_@;5~|M* z=O+n2P58*u@%$O8o%L(ysCJ&(eDw5T{!OY~@M&*RZOX4*q}sF+iex*UcIPiq?XpjM zn`-ZT<{#QNL2G&x*QG^{T2w+n#ps0*vprbUf1~M%Da>du+t} KI7ELUwfJ8SC5J5l literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/utils.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/utils.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..676db229a4d8633f85c3b9099c2294a536a1fe64 GIT binary patch literal 37071 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 literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/visitor.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/visitor.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..424b6964d2c9d0a179237fdff3be49e07fef614a GIT binary patch literal 5725 zcmb7IU2Gf25#Bo^@yWJq)3%gEQBpfi8px8JI0;lYQk+&%K%RIj>7>&g zeRq;9l>$^C1@vG9OkYf(3Bb0Ft28MPpeW#nJmkR-1`-sMLBPbJ1`HGdnl}bcfg(?x z*(E9dNJVnIo144cotv4Ro%xo3Zfy+_IKKZ=LM^ot@-KX-9NseXCV5dKOd-wyyYR}6S(*>8Dzcu&?|6D zgci8UEg{wtgq9EuHH>Oe#c>jAS-UcP`I0VbZW_pp@tTzqsW@!Sf-t#Nk=n{fzUUo!q_(g(3s##V<0KX zwc@m5%%f3wzCkFN6u>p2Do~FqQfbE-s;BNrs(qRXfODitpXvis{BG+N&DNX|Mc0*S zow^dL?@Ed_YrDRM6@IsIr!MM>z0m&_o$en_rTQn99MjSi zeQIEt8p~6!YtvJpDeX@w$pvMW+EeqIF|Q0hxr_#w)#8$rpz=P9 zx}a(sq!^BDjywXEjDZ_qq@gU*c-#%e3ODgJ0M^ zB;JFT+K`xJA%Ux9Mq(50#Snot;hRVM*`fODo;;gRKpltu_j4Z8d~p zgi#8wmJD@3mM384H4j)+R%ITz^0J~YQCnV_(~@)YiU#thDH8)r7(!g#S)vIhCn3Y? zoHNyd5bJdrmaIx=lqKC^syBa&r2^0b)v{&9qH-c}f_00ZNF?ObOiU7@+mYchQ zgprIn{m~eZ8^pn^R6f#BF&u2GJPWs=^^+Y{T7^M%OyeBeCKRn_EQH)U9`S>c!m<_1ZV z9Ne3abi;J5OKIshVUeVzv@k2A#Xkyf5RIfgH--0vaRTqje06Gf>k$*yc%_4-#+Dtp zC8mF^K^C;2tRWd%WU}c!$|L@Q;78Dj^!g~x1vD!`B_() z4V+~juJbEa2Iki*z<^(c9Ne3aTkz_W>g!SRPUpJR;616)zXG`)Rl&HdxNTki6h;B_g>VN(0du$aD;NdLo`f%Rv?2*t^+3Fb$D<7(yFn7_oyTZp zhbq-Qd8q`z!v_$;&wz)guC=kRcL&~6X@5l|0SSHvLIM!8K{tYdGGQr(4P|L79P{El9Q&)KwV}%+EITy<1Alj)wj7FhQN-C8K zhoLPML{$C&#~3q~xyU}1vM9ibC0o`_?gQC`f!2x!)@aTNyP}~AVw|}e19x;`(4?Xw z2V*j#Ge9S(1AzQl1U_6D%_!qERuc`Ai79&lw^OpCEC9x0Ua5r*)oNoQfT&B2h!R+8 z{5MSek4TOGoPtuhF0Fg(aD>;9s*y(O_m0-JS+ed+dm*hZto!Rm`JHOWlg3dmu>@R| zn)Wv);B|l6zad;d{X-?%U1?tqb7s?#_Sd5zNbOgkZ;fs{Lw4z_r@=ZE_T#@5Ux1F+ ze^;lG_y5@VY=e#7CL06kz(%`+^He_4LRzZ#FKGLvgWIi|9_c_ma)Uk((on1{-0H#V zZ(%iOMx(lFyCHy*fH)N+342@}pe)bYn5JDHz2;Cub$v<-cBHE7SELgZA5w6{J}Jajk{Djqss zB7ydPMlu&3bob`^{uAVl!))~zM_08C*2HfJ)4)$e>Mb!pSPdm_pG;gP|m(s z>^b(J_w?3 z@bmU@e$NDood@%sM;}BFW=C^<+tHJS=*c`gzvi#D_H9Q83(>)Rbnw5$NatotGhD*e z!E(Ycfw{o}Byjv_29WDgU8GBU=K$N21^_hp(WDzmgb0bcG}u^+pl?z>UKnU^x5%<}Pnwtu^FK(A$x95S?{w4S#xp zF}Hv5`J0US;_98{yXu`Zd)Sk3*o5lE!pu6?2OBlml`{ifFG~~r&!*OiUtPWsA9>}% z$ZMCzUUu7gzc|ZOHsTRibf_D+Y?+RkGCdB>+ z5Wu*CP!dH!g2fEPM}*Ei>EP!>(w(nAA9|#BUxIZiv=yZz`N~<6L~k36Zz5UogO+dc n{dYT!p~C{8%4YH{zWZ*cVN^IJbd*Rl$t-+}Z@=56iFx;bc4MPU literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/_identifier.py b/.venv/Lib/site-packages/jinja2/_identifier.py new file mode 100644 index 000000000..928c1503c --- /dev/null +++ b/.venv/Lib/site-packages/jinja2/_identifier.py @@ -0,0 +1,6 @@ +import re + +# generated by scripts/generate_identifier_pattern.py +pattern = re.compile( + r"[\w·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߽߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛࣓-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣঁ-ঃ়া-ৄেৈো-্ৗৢৣ৾ਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑੰੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣૺ-૿ଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣஂா-ூெ-ைொ-்ௗఀ-ఄా-ౄె-ైొ-్ౕౖౢౣಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣഀ-ഃ഻഼ാ-ൄെ-ൈൊ-്ൗൢൣංඃ්ා-ුූෘ-ෟෲෳัิ-ฺ็-๎ັິ-ູົຼ່-ໍ༹༘༙༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏႚ-ႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝᠋-᠍ᢅᢆᢩᤠ-ᤫᤰ-᤻ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼᪰-᪽ᬀ-ᬄ᬴-᭄᭫-᭳ᮀ-ᮂᮡ-ᮭ᯦-᯳ᰤ-᰷᳐-᳔᳒-᳨᳭ᳲ-᳴᳷-᳹᷀-᷹᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰℘℮⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-ꣅ꣠-꣱ꣿꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀ꧥꨩ-ꨶꩃꩌꩍꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭ﬞ︀-️︠-︯︳︴﹍-﹏_𐇽𐋠𐍶-𐍺𐨁-𐨃𐨅𐨆𐨌-𐨏𐨸-𐨿𐨺𐫦𐫥𐴤-𐽆𐴧-𐽐𑀀-𑀂𑀸-𑁆𑁿-𑂂𑂰-𑂺𑄀-𑄂𑄧-𑄴𑅅𑅆𑅳𑆀-𑆂𑆳-𑇀𑇉-𑇌𑈬-𑈷𑈾𑋟-𑋪𑌀-𑌃𑌻𑌼𑌾-𑍄𑍇𑍈𑍋-𑍍𑍗𑍢𑍣𑍦-𑍬𑍰-𑍴𑐵-𑑆𑑞𑒰-𑓃𑖯-𑖵𑖸-𑗀𑗜𑗝𑘰-𑙀𑚫-𑚷𑜝-𑜫𑠬-𑠺𑨁-𑨊𑨳-𑨹𑨻-𑨾𑩇𑩑-𑩛𑪊-𑪙𑰯-𑰶𑰸-𑰿𑲒-𑲧𑲩-𑲶𑴱-𑴶𑴺𑴼𑴽𑴿-𑵅𑵇𑶊-𑶎𑶐𑶑𑶓-𑶗𑻳-𑻶𖫰-𖫴𖬰-𖬶𖽑-𖽾𖾏-𖾒𛲝𛲞𝅥-𝅩𝅭-𝅲𝅻-𝆂𝆅-𝆋𝆪-𝆭𝉂-𝉄𝨀-𝨶𝨻-𝩬𝩵𝪄𝪛-𝪟𝪡-𝪯𞀀-𞀆𞀈-𞀘𞀛-𞀡𞀣𞀤𞀦-𞣐𞀪-𞣖𞥄-𞥊󠄀-󠇯]+" # noqa: B950 +) diff --git a/.venv/Lib/site-packages/jinja2/async_utils.py b/.venv/Lib/site-packages/jinja2/async_utils.py new file mode 100644 index 000000000..1a4f3892c --- /dev/null +++ b/.venv/Lib/site-packages/jinja2/async_utils.py @@ -0,0 +1,84 @@ +import inspect +import typing as t +from functools import WRAPPER_ASSIGNMENTS +from functools import wraps + +from .utils import _PassArg +from .utils import pass_eval_context + +V = t.TypeVar("V") + + +def async_variant(normal_func): # type: ignore + def decorator(async_func): # type: ignore + pass_arg = _PassArg.from_obj(normal_func) + need_eval_context = pass_arg is None + + if pass_arg is _PassArg.environment: + + def is_async(args: t.Any) -> bool: + return t.cast(bool, args[0].is_async) + + else: + + def is_async(args: t.Any) -> bool: + return t.cast(bool, args[0].environment.is_async) + + # Take the doc and annotations from the sync function, but the + # name from the async function. Pallets-Sphinx-Themes + # build_function_directive expects __wrapped__ to point to the + # sync function. + async_func_attrs = ("__module__", "__name__", "__qualname__") + normal_func_attrs = tuple(set(WRAPPER_ASSIGNMENTS).difference(async_func_attrs)) + + @wraps(normal_func, assigned=normal_func_attrs) + @wraps(async_func, assigned=async_func_attrs, updated=()) + def wrapper(*args, **kwargs): # type: ignore + b = is_async(args) + + if need_eval_context: + args = args[1:] + + if b: + return async_func(*args, **kwargs) + + return normal_func(*args, **kwargs) + + if need_eval_context: + wrapper = pass_eval_context(wrapper) + + wrapper.jinja_async_variant = True + return wrapper + + return decorator + + +_common_primitives = {int, float, bool, str, list, dict, tuple, type(None)} + + +async def auto_await(value: t.Union[t.Awaitable["V"], "V"]) -> "V": + # Avoid a costly call to isawaitable + if type(value) in _common_primitives: + return t.cast("V", value) + + if inspect.isawaitable(value): + return await t.cast("t.Awaitable[V]", value) + + return t.cast("V", value) + + +async def auto_aiter( + iterable: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", +) -> "t.AsyncIterator[V]": + if hasattr(iterable, "__aiter__"): + async for item in t.cast("t.AsyncIterable[V]", iterable): + yield item + else: + for item in t.cast("t.Iterable[V]", iterable): + yield item + + +async def auto_to_list( + value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", +) -> t.List["V"]: + return [x async for x in auto_aiter(value)] diff --git a/.venv/Lib/site-packages/jinja2/bccache.py b/.venv/Lib/site-packages/jinja2/bccache.py new file mode 100644 index 000000000..d0ddf56ef --- /dev/null +++ b/.venv/Lib/site-packages/jinja2/bccache.py @@ -0,0 +1,406 @@ +"""The optional bytecode cache system. This is useful if you have very +complex template situations and the compilation of all those templates +slows down your application too much. + +Situations where this is useful are often forking web applications that +are initialized on the first request. +""" +import errno +import fnmatch +import marshal +import os +import pickle +import stat +import sys +import tempfile +import typing as t +from hashlib import sha1 +from io import BytesIO +from types import CodeType + +if t.TYPE_CHECKING: + import typing_extensions as te + from .environment import Environment + + class _MemcachedClient(te.Protocol): + def get(self, key: str) -> bytes: + ... + + def set(self, key: str, value: bytes, timeout: t.Optional[int] = None) -> None: + ... + + +bc_version = 5 +# Magic bytes to identify Jinja bytecode cache files. Contains the +# Python major and minor version to avoid loading incompatible bytecode +# if a project upgrades its Python version. +bc_magic = ( + b"j2" + + pickle.dumps(bc_version, 2) + + pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1], 2) +) + + +class Bucket: + """Buckets are used to store the bytecode for one template. It's created + and initialized by the bytecode cache and passed to the loading functions. + + The buckets get an internal checksum from the cache assigned and use this + to automatically reject outdated cache material. Individual bytecode + cache subclasses don't have to care about cache invalidation. + """ + + def __init__(self, environment: "Environment", key: str, checksum: str) -> None: + self.environment = environment + self.key = key + self.checksum = checksum + self.reset() + + def reset(self) -> None: + """Resets the bucket (unloads the bytecode).""" + self.code: t.Optional[CodeType] = None + + def load_bytecode(self, f: t.BinaryIO) -> None: + """Loads bytecode from a file or file like object.""" + # make sure the magic header is correct + magic = f.read(len(bc_magic)) + if magic != bc_magic: + self.reset() + return + # the source code of the file changed, we need to reload + checksum = pickle.load(f) + if self.checksum != checksum: + self.reset() + return + # if marshal_load fails then we need to reload + try: + self.code = marshal.load(f) + except (EOFError, ValueError, TypeError): + self.reset() + return + + def write_bytecode(self, f: t.IO[bytes]) -> None: + """Dump the bytecode into the file or file like object passed.""" + if self.code is None: + raise TypeError("can't write empty bucket") + f.write(bc_magic) + pickle.dump(self.checksum, f, 2) + marshal.dump(self.code, f) + + def bytecode_from_string(self, string: bytes) -> None: + """Load bytecode from bytes.""" + self.load_bytecode(BytesIO(string)) + + def bytecode_to_string(self) -> bytes: + """Return the bytecode as bytes.""" + out = BytesIO() + self.write_bytecode(out) + return out.getvalue() + + +class BytecodeCache: + """To implement your own bytecode cache you have to subclass this class + and override :meth:`load_bytecode` and :meth:`dump_bytecode`. Both of + these methods are passed a :class:`~jinja2.bccache.Bucket`. + + A very basic bytecode cache that saves the bytecode on the file system:: + + from os import path + + class MyCache(BytecodeCache): + + def __init__(self, directory): + self.directory = directory + + def load_bytecode(self, bucket): + filename = path.join(self.directory, bucket.key) + if path.exists(filename): + with open(filename, 'rb') as f: + bucket.load_bytecode(f) + + def dump_bytecode(self, bucket): + filename = path.join(self.directory, bucket.key) + with open(filename, 'wb') as f: + bucket.write_bytecode(f) + + A more advanced version of a filesystem based bytecode cache is part of + Jinja. + """ + + def load_bytecode(self, bucket: Bucket) -> None: + """Subclasses have to override this method to load bytecode into a + bucket. If they are not able to find code in the cache for the + bucket, it must not do anything. + """ + raise NotImplementedError() + + def dump_bytecode(self, bucket: Bucket) -> None: + """Subclasses have to override this method to write the bytecode + from a bucket back to the cache. If it unable to do so it must not + fail silently but raise an exception. + """ + raise NotImplementedError() + + def clear(self) -> None: + """Clears the cache. This method is not used by Jinja but should be + implemented to allow applications to clear the bytecode cache used + by a particular environment. + """ + + def get_cache_key( + self, name: str, filename: t.Optional[t.Union[str]] = None + ) -> str: + """Returns the unique hash key for this template name.""" + hash = sha1(name.encode("utf-8")) + + if filename is not None: + hash.update(f"|{filename}".encode()) + + return hash.hexdigest() + + def get_source_checksum(self, source: str) -> str: + """Returns a checksum for the source.""" + return sha1(source.encode("utf-8")).hexdigest() + + def get_bucket( + self, + environment: "Environment", + name: str, + filename: t.Optional[str], + source: str, + ) -> Bucket: + """Return a cache bucket for the given template. All arguments are + mandatory but filename may be `None`. + """ + key = self.get_cache_key(name, filename) + checksum = self.get_source_checksum(source) + bucket = Bucket(environment, key, checksum) + self.load_bytecode(bucket) + return bucket + + def set_bucket(self, bucket: Bucket) -> None: + """Put the bucket into the cache.""" + self.dump_bytecode(bucket) + + +class FileSystemBytecodeCache(BytecodeCache): + """A bytecode cache that stores bytecode on the filesystem. It accepts + two arguments: The directory where the cache items are stored and a + pattern string that is used to build the filename. + + If no directory is specified a default cache directory is selected. On + Windows the user's temp directory is used, on UNIX systems a directory + is created for the user in the system temp directory. + + The pattern can be used to have multiple separate caches operate on the + same directory. The default pattern is ``'__jinja2_%s.cache'``. ``%s`` + is replaced with the cache key. + + >>> bcc = FileSystemBytecodeCache('/tmp/jinja_cache', '%s.cache') + + This bytecode cache supports clearing of the cache using the clear method. + """ + + def __init__( + self, directory: t.Optional[str] = None, pattern: str = "__jinja2_%s.cache" + ) -> None: + if directory is None: + directory = self._get_default_cache_dir() + self.directory = directory + self.pattern = pattern + + def _get_default_cache_dir(self) -> str: + def _unsafe_dir() -> "te.NoReturn": + raise RuntimeError( + "Cannot determine safe temp directory. You " + "need to explicitly provide one." + ) + + tmpdir = tempfile.gettempdir() + + # On windows the temporary directory is used specific unless + # explicitly forced otherwise. We can just use that. + if os.name == "nt": + return tmpdir + if not hasattr(os, "getuid"): + _unsafe_dir() + + dirname = f"_jinja2-cache-{os.getuid()}" + actual_dir = os.path.join(tmpdir, dirname) + + try: + os.mkdir(actual_dir, stat.S_IRWXU) + except OSError as e: + if e.errno != errno.EEXIST: + raise + try: + os.chmod(actual_dir, stat.S_IRWXU) + actual_dir_stat = os.lstat(actual_dir) + if ( + actual_dir_stat.st_uid != os.getuid() + or not stat.S_ISDIR(actual_dir_stat.st_mode) + or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU + ): + _unsafe_dir() + except OSError as e: + if e.errno != errno.EEXIST: + raise + + actual_dir_stat = os.lstat(actual_dir) + if ( + actual_dir_stat.st_uid != os.getuid() + or not stat.S_ISDIR(actual_dir_stat.st_mode) + or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU + ): + _unsafe_dir() + + return actual_dir + + def _get_cache_filename(self, bucket: Bucket) -> str: + return os.path.join(self.directory, self.pattern % (bucket.key,)) + + def load_bytecode(self, bucket: Bucket) -> None: + filename = self._get_cache_filename(bucket) + + # Don't test for existence before opening the file, since the + # file could disappear after the test before the open. + try: + f = open(filename, "rb") + except (FileNotFoundError, IsADirectoryError, PermissionError): + # PermissionError can occur on Windows when an operation is + # in progress, such as calling clear(). + return + + with f: + bucket.load_bytecode(f) + + def dump_bytecode(self, bucket: Bucket) -> None: + # Write to a temporary file, then rename to the real name after + # writing. This avoids another process reading the file before + # it is fully written. + name = self._get_cache_filename(bucket) + f = tempfile.NamedTemporaryFile( + mode="wb", + dir=os.path.dirname(name), + prefix=os.path.basename(name), + suffix=".tmp", + delete=False, + ) + + def remove_silent() -> None: + try: + os.remove(f.name) + except OSError: + # Another process may have called clear(). On Windows, + # another program may be holding the file open. + pass + + try: + with f: + bucket.write_bytecode(f) + except BaseException: + remove_silent() + raise + + try: + os.replace(f.name, name) + except OSError: + # Another process may have called clear(). On Windows, + # another program may be holding the file open. + remove_silent() + except BaseException: + remove_silent() + raise + + def clear(self) -> None: + # imported lazily here because google app-engine doesn't support + # write access on the file system and the function does not exist + # normally. + from os import remove + + files = fnmatch.filter(os.listdir(self.directory), self.pattern % ("*",)) + for filename in files: + try: + remove(os.path.join(self.directory, filename)) + except OSError: + pass + + +class MemcachedBytecodeCache(BytecodeCache): + """This class implements a bytecode cache that uses a memcache cache for + storing the information. It does not enforce a specific memcache library + (tummy's memcache or cmemcache) but will accept any class that provides + the minimal interface required. + + Libraries compatible with this class: + + - `cachelib `_ + - `python-memcached `_ + + (Unfortunately the django cache interface is not compatible because it + does not support storing binary data, only text. You can however pass + the underlying cache client to the bytecode cache which is available + as `django.core.cache.cache._client`.) + + The minimal interface for the client passed to the constructor is this: + + .. class:: MinimalClientInterface + + .. method:: set(key, value[, timeout]) + + Stores the bytecode in the cache. `value` is a string and + `timeout` the timeout of the key. If timeout is not provided + a default timeout or no timeout should be assumed, if it's + provided it's an integer with the number of seconds the cache + item should exist. + + .. method:: get(key) + + Returns the value for the cache key. If the item does not + exist in the cache the return value must be `None`. + + The other arguments to the constructor are the prefix for all keys that + is added before the actual cache key and the timeout for the bytecode in + the cache system. We recommend a high (or no) timeout. + + This bytecode cache does not support clearing of used items in the cache. + The clear method is a no-operation function. + + .. versionadded:: 2.7 + Added support for ignoring memcache errors through the + `ignore_memcache_errors` parameter. + """ + + def __init__( + self, + client: "_MemcachedClient", + prefix: str = "jinja2/bytecode/", + timeout: t.Optional[int] = None, + ignore_memcache_errors: bool = True, + ): + self.client = client + self.prefix = prefix + self.timeout = timeout + self.ignore_memcache_errors = ignore_memcache_errors + + def load_bytecode(self, bucket: Bucket) -> None: + try: + code = self.client.get(self.prefix + bucket.key) + except Exception: + if not self.ignore_memcache_errors: + raise + else: + bucket.bytecode_from_string(code) + + def dump_bytecode(self, bucket: Bucket) -> None: + key = self.prefix + bucket.key + value = bucket.bytecode_to_string() + + try: + if self.timeout is not None: + self.client.set(key, value, self.timeout) + else: + self.client.set(key, value) + except Exception: + if not self.ignore_memcache_errors: + raise diff --git a/.venv/Lib/site-packages/jinja2/compiler.py b/.venv/Lib/site-packages/jinja2/compiler.py new file mode 100644 index 000000000..3458095f5 --- /dev/null +++ b/.venv/Lib/site-packages/jinja2/compiler.py @@ -0,0 +1,1957 @@ +"""Compiles nodes from the parser into Python code.""" +import typing as t +from contextlib import contextmanager +from functools import update_wrapper +from io import StringIO +from itertools import chain +from keyword import iskeyword as is_python_keyword + +from markupsafe import escape +from markupsafe import Markup + +from . import nodes +from .exceptions import TemplateAssertionError +from .idtracking import Symbols +from .idtracking import VAR_LOAD_ALIAS +from .idtracking import VAR_LOAD_PARAMETER +from .idtracking import VAR_LOAD_RESOLVE +from .idtracking import VAR_LOAD_UNDEFINED +from .nodes import EvalContext +from .optimizer import Optimizer +from .utils import _PassArg +from .utils import concat +from .visitor import NodeVisitor + +if t.TYPE_CHECKING: + import typing_extensions as te + from .environment import Environment + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + +operators = { + "eq": "==", + "ne": "!=", + "gt": ">", + "gteq": ">=", + "lt": "<", + "lteq": "<=", + "in": "in", + "notin": "not in", +} + + +def optimizeconst(f: F) -> F: + def new_func( + self: "CodeGenerator", node: nodes.Expr, frame: "Frame", **kwargs: t.Any + ) -> t.Any: + # Only optimize if the frame is not volatile + if self.optimizer is not None and not frame.eval_ctx.volatile: + new_node = self.optimizer.visit(node, frame.eval_ctx) + + if new_node != node: + return self.visit(new_node, frame) + + return f(self, node, frame, **kwargs) + + return update_wrapper(t.cast(F, new_func), f) + + +def _make_binop(op: str) -> t.Callable[["CodeGenerator", nodes.BinExpr, "Frame"], None]: + @optimizeconst + def visitor(self: "CodeGenerator", node: nodes.BinExpr, frame: Frame) -> None: + if ( + self.environment.sandboxed + and op in self.environment.intercepted_binops # type: ignore + ): + self.write(f"environment.call_binop(context, {op!r}, ") + self.visit(node.left, frame) + self.write(", ") + self.visit(node.right, frame) + else: + self.write("(") + self.visit(node.left, frame) + self.write(f" {op} ") + self.visit(node.right, frame) + + self.write(")") + + return visitor + + +def _make_unop( + op: str, +) -> t.Callable[["CodeGenerator", nodes.UnaryExpr, "Frame"], None]: + @optimizeconst + def visitor(self: "CodeGenerator", node: nodes.UnaryExpr, frame: Frame) -> None: + if ( + self.environment.sandboxed + and op in self.environment.intercepted_unops # type: ignore + ): + self.write(f"environment.call_unop(context, {op!r}, ") + self.visit(node.node, frame) + else: + self.write("(" + op) + self.visit(node.node, frame) + + self.write(")") + + return visitor + + +def generate( + node: nodes.Template, + environment: "Environment", + name: t.Optional[str], + filename: t.Optional[str], + stream: t.Optional[t.TextIO] = None, + defer_init: bool = False, + optimized: bool = True, +) -> t.Optional[str]: + """Generate the python source for a node tree.""" + if not isinstance(node, nodes.Template): + raise TypeError("Can't compile non template nodes") + + generator = environment.code_generator_class( + environment, name, filename, stream, defer_init, optimized + ) + generator.visit(node) + + if stream is None: + return generator.stream.getvalue() # type: ignore + + return None + + +def has_safe_repr(value: t.Any) -> bool: + """Does the node have a safe representation?""" + if value is None or value is NotImplemented or value is Ellipsis: + return True + + if type(value) in {bool, int, float, complex, range, str, Markup}: + return True + + if type(value) in {tuple, list, set, frozenset}: + return all(has_safe_repr(v) for v in value) + + if type(value) is dict: + return all(has_safe_repr(k) and has_safe_repr(v) for k, v in value.items()) + + return False + + +def find_undeclared( + nodes: t.Iterable[nodes.Node], names: t.Iterable[str] +) -> t.Set[str]: + """Check if the names passed are accessed undeclared. The return value + is a set of all the undeclared names from the sequence of names found. + """ + visitor = UndeclaredNameVisitor(names) + try: + for node in nodes: + visitor.visit(node) + except VisitorExit: + pass + return visitor.undeclared + + +class MacroRef: + def __init__(self, node: t.Union[nodes.Macro, nodes.CallBlock]) -> None: + self.node = node + self.accesses_caller = False + self.accesses_kwargs = False + self.accesses_varargs = False + + +class Frame: + """Holds compile time information for us.""" + + def __init__( + self, + eval_ctx: EvalContext, + parent: t.Optional["Frame"] = None, + level: t.Optional[int] = None, + ) -> None: + self.eval_ctx = eval_ctx + + # the parent of this frame + self.parent = parent + + if parent is None: + self.symbols = Symbols(level=level) + + # in some dynamic inheritance situations the compiler needs to add + # write tests around output statements. + self.require_output_check = False + + # inside some tags we are using a buffer rather than yield statements. + # this for example affects {% filter %} or {% macro %}. If a frame + # is buffered this variable points to the name of the list used as + # buffer. + self.buffer: t.Optional[str] = None + + # the name of the block we're in, otherwise None. + self.block: t.Optional[str] = None + + else: + self.symbols = Symbols(parent.symbols, level=level) + self.require_output_check = parent.require_output_check + self.buffer = parent.buffer + self.block = parent.block + + # a toplevel frame is the root + soft frames such as if conditions. + self.toplevel = False + + # the root frame is basically just the outermost frame, so no if + # conditions. This information is used to optimize inheritance + # situations. + self.rootlevel = False + + # variables set inside of loops and blocks should not affect outer frames, + # but they still needs to be kept track of as part of the active context. + self.loop_frame = False + self.block_frame = False + + # track whether the frame is being used in an if-statement or conditional + # expression as it determines which errors should be raised during runtime + # or compile time. + self.soft_frame = False + + def copy(self) -> "Frame": + """Create a copy of the current one.""" + rv = object.__new__(self.__class__) + rv.__dict__.update(self.__dict__) + rv.symbols = self.symbols.copy() + return rv + + def inner(self, isolated: bool = False) -> "Frame": + """Return an inner frame.""" + if isolated: + return Frame(self.eval_ctx, level=self.symbols.level + 1) + return Frame(self.eval_ctx, self) + + def soft(self) -> "Frame": + """Return a soft frame. A soft frame may not be modified as + standalone thing as it shares the resources with the frame it + was created of, but it's not a rootlevel frame any longer. + + This is only used to implement if-statements and conditional + expressions. + """ + rv = self.copy() + rv.rootlevel = False + rv.soft_frame = True + return rv + + __copy__ = copy + + +class VisitorExit(RuntimeError): + """Exception used by the `UndeclaredNameVisitor` to signal a stop.""" + + +class DependencyFinderVisitor(NodeVisitor): + """A visitor that collects filter and test calls.""" + + def __init__(self) -> None: + self.filters: t.Set[str] = set() + self.tests: t.Set[str] = set() + + def visit_Filter(self, node: nodes.Filter) -> None: + self.generic_visit(node) + self.filters.add(node.name) + + def visit_Test(self, node: nodes.Test) -> None: + self.generic_visit(node) + self.tests.add(node.name) + + def visit_Block(self, node: nodes.Block) -> None: + """Stop visiting at blocks.""" + + +class UndeclaredNameVisitor(NodeVisitor): + """A visitor that checks if a name is accessed without being + declared. This is different from the frame visitor as it will + not stop at closure frames. + """ + + def __init__(self, names: t.Iterable[str]) -> None: + self.names = set(names) + self.undeclared: t.Set[str] = set() + + def visit_Name(self, node: nodes.Name) -> None: + if node.ctx == "load" and node.name in self.names: + self.undeclared.add(node.name) + if self.undeclared == self.names: + raise VisitorExit() + else: + self.names.discard(node.name) + + def visit_Block(self, node: nodes.Block) -> None: + """Stop visiting a blocks.""" + + +class CompilerExit(Exception): + """Raised if the compiler encountered a situation where it just + doesn't make sense to further process the code. Any block that + raises such an exception is not further processed. + """ + + +class CodeGenerator(NodeVisitor): + def __init__( + self, + environment: "Environment", + name: t.Optional[str], + filename: t.Optional[str], + stream: t.Optional[t.TextIO] = None, + defer_init: bool = False, + optimized: bool = True, + ) -> None: + if stream is None: + stream = StringIO() + self.environment = environment + self.name = name + self.filename = filename + self.stream = stream + self.created_block_context = False + self.defer_init = defer_init + self.optimizer: t.Optional[Optimizer] = None + + if optimized: + self.optimizer = Optimizer(environment) + + # aliases for imports + self.import_aliases: t.Dict[str, str] = {} + + # a registry for all blocks. Because blocks are moved out + # into the global python scope they are registered here + self.blocks: t.Dict[str, nodes.Block] = {} + + # the number of extends statements so far + self.extends_so_far = 0 + + # some templates have a rootlevel extends. In this case we + # can safely assume that we're a child template and do some + # more optimizations. + self.has_known_extends = False + + # the current line number + self.code_lineno = 1 + + # registry of all filters and tests (global, not block local) + self.tests: t.Dict[str, str] = {} + self.filters: t.Dict[str, str] = {} + + # the debug information + self.debug_info: t.List[t.Tuple[int, int]] = [] + self._write_debug_info: t.Optional[int] = None + + # the number of new lines before the next write() + self._new_lines = 0 + + # the line number of the last written statement + self._last_line = 0 + + # true if nothing was written so far. + self._first_write = True + + # used by the `temporary_identifier` method to get new + # unique, temporary identifier + self._last_identifier = 0 + + # the current indentation + self._indentation = 0 + + # Tracks toplevel assignments + self._assign_stack: t.List[t.Set[str]] = [] + + # Tracks parameter definition blocks + self._param_def_block: t.List[t.Set[str]] = [] + + # Tracks the current context. + self._context_reference_stack = ["context"] + + @property + def optimized(self) -> bool: + return self.optimizer is not None + + # -- Various compilation helpers + + def fail(self, msg: str, lineno: int) -> "te.NoReturn": + """Fail with a :exc:`TemplateAssertionError`.""" + raise TemplateAssertionError(msg, lineno, self.name, self.filename) + + def temporary_identifier(self) -> str: + """Get a new unique identifier.""" + self._last_identifier += 1 + return f"t_{self._last_identifier}" + + def buffer(self, frame: Frame) -> None: + """Enable buffering for the frame from that point onwards.""" + frame.buffer = self.temporary_identifier() + self.writeline(f"{frame.buffer} = []") + + def return_buffer_contents( + self, frame: Frame, force_unescaped: bool = False + ) -> None: + """Return the buffer contents of the frame.""" + if not force_unescaped: + if frame.eval_ctx.volatile: + self.writeline("if context.eval_ctx.autoescape:") + self.indent() + self.writeline(f"return Markup(concat({frame.buffer}))") + self.outdent() + self.writeline("else:") + self.indent() + self.writeline(f"return concat({frame.buffer})") + self.outdent() + return + elif frame.eval_ctx.autoescape: + self.writeline(f"return Markup(concat({frame.buffer}))") + return + self.writeline(f"return concat({frame.buffer})") + + def indent(self) -> None: + """Indent by one.""" + self._indentation += 1 + + def outdent(self, step: int = 1) -> None: + """Outdent by step.""" + self._indentation -= step + + def start_write(self, frame: Frame, node: t.Optional[nodes.Node] = None) -> None: + """Yield or write into the frame buffer.""" + if frame.buffer is None: + self.writeline("yield ", node) + else: + self.writeline(f"{frame.buffer}.append(", node) + + def end_write(self, frame: Frame) -> None: + """End the writing process started by `start_write`.""" + if frame.buffer is not None: + self.write(")") + + def simple_write( + self, s: str, frame: Frame, node: t.Optional[nodes.Node] = None + ) -> None: + """Simple shortcut for start_write + write + end_write.""" + self.start_write(frame, node) + self.write(s) + self.end_write(frame) + + def blockvisit(self, nodes: t.Iterable[nodes.Node], frame: Frame) -> None: + """Visit a list of nodes as block in a frame. If the current frame + is no buffer a dummy ``if 0: yield None`` is written automatically. + """ + try: + self.writeline("pass") + for node in nodes: + self.visit(node, frame) + except CompilerExit: + pass + + def write(self, x: str) -> None: + """Write a string into the output stream.""" + if self._new_lines: + if not self._first_write: + self.stream.write("\n" * self._new_lines) + self.code_lineno += self._new_lines + if self._write_debug_info is not None: + self.debug_info.append((self._write_debug_info, self.code_lineno)) + self._write_debug_info = None + self._first_write = False + self.stream.write(" " * self._indentation) + self._new_lines = 0 + self.stream.write(x) + + def writeline( + self, x: str, node: t.Optional[nodes.Node] = None, extra: int = 0 + ) -> None: + """Combination of newline and write.""" + self.newline(node, extra) + self.write(x) + + def newline(self, node: t.Optional[nodes.Node] = None, extra: int = 0) -> None: + """Add one or more newlines before the next write.""" + self._new_lines = max(self._new_lines, 1 + extra) + if node is not None and node.lineno != self._last_line: + self._write_debug_info = node.lineno + self._last_line = node.lineno + + def signature( + self, + node: t.Union[nodes.Call, nodes.Filter, nodes.Test], + frame: Frame, + extra_kwargs: t.Optional[t.Mapping[str, t.Any]] = None, + ) -> None: + """Writes a function call to the stream for the current node. + A leading comma is added automatically. The extra keyword + arguments may not include python keywords otherwise a syntax + error could occur. The extra keyword arguments should be given + as python dict. + """ + # if any of the given keyword arguments is a python keyword + # we have to make sure that no invalid call is created. + kwarg_workaround = any( + is_python_keyword(t.cast(str, k)) + for k in chain((x.key for x in node.kwargs), extra_kwargs or ()) + ) + + for arg in node.args: + self.write(", ") + self.visit(arg, frame) + + if not kwarg_workaround: + for kwarg in node.kwargs: + self.write(", ") + self.visit(kwarg, frame) + if extra_kwargs is not None: + for key, value in extra_kwargs.items(): + self.write(f", {key}={value}") + if node.dyn_args: + self.write(", *") + self.visit(node.dyn_args, frame) + + if kwarg_workaround: + if node.dyn_kwargs is not None: + self.write(", **dict({") + else: + self.write(", **{") + for kwarg in node.kwargs: + self.write(f"{kwarg.key!r}: ") + self.visit(kwarg.value, frame) + self.write(", ") + if extra_kwargs is not None: + for key, value in extra_kwargs.items(): + self.write(f"{key!r}: {value}, ") + if node.dyn_kwargs is not None: + self.write("}, **") + self.visit(node.dyn_kwargs, frame) + self.write(")") + else: + self.write("}") + + elif node.dyn_kwargs is not None: + self.write(", **") + self.visit(node.dyn_kwargs, frame) + + def pull_dependencies(self, nodes: t.Iterable[nodes.Node]) -> None: + """Find all filter and test names used in the template and + assign them to variables in the compiled namespace. Checking + that the names are registered with the environment is done when + compiling the Filter and Test nodes. If the node is in an If or + CondExpr node, the check is done at runtime instead. + + .. versionchanged:: 3.0 + Filters and tests in If and CondExpr nodes are checked at + runtime instead of compile time. + """ + visitor = DependencyFinderVisitor() + + for node in nodes: + visitor.visit(node) + + for id_map, names, dependency in (self.filters, visitor.filters, "filters"), ( + self.tests, + visitor.tests, + "tests", + ): + for name in sorted(names): + if name not in id_map: + id_map[name] = self.temporary_identifier() + + # add check during runtime that dependencies used inside of executed + # blocks are defined, as this step may be skipped during compile time + self.writeline("try:") + self.indent() + self.writeline(f"{id_map[name]} = environment.{dependency}[{name!r}]") + self.outdent() + self.writeline("except KeyError:") + self.indent() + self.writeline("@internalcode") + self.writeline(f"def {id_map[name]}(*unused):") + self.indent() + self.writeline( + f'raise TemplateRuntimeError("No {dependency[:-1]}' + f' named {name!r} found.")' + ) + self.outdent() + self.outdent() + + def enter_frame(self, frame: Frame) -> None: + undefs = [] + for target, (action, param) in frame.symbols.loads.items(): + if action == VAR_LOAD_PARAMETER: + pass + elif action == VAR_LOAD_RESOLVE: + self.writeline(f"{target} = {self.get_resolve_func()}({param!r})") + elif action == VAR_LOAD_ALIAS: + self.writeline(f"{target} = {param}") + elif action == VAR_LOAD_UNDEFINED: + undefs.append(target) + else: + raise NotImplementedError("unknown load instruction") + if undefs: + self.writeline(f"{' = '.join(undefs)} = missing") + + def leave_frame(self, frame: Frame, with_python_scope: bool = False) -> None: + if not with_python_scope: + undefs = [] + for target in frame.symbols.loads: + undefs.append(target) + if undefs: + self.writeline(f"{' = '.join(undefs)} = missing") + + def choose_async(self, async_value: str = "async ", sync_value: str = "") -> str: + return async_value if self.environment.is_async else sync_value + + def func(self, name: str) -> str: + return f"{self.choose_async()}def {name}" + + def macro_body( + self, node: t.Union[nodes.Macro, nodes.CallBlock], frame: Frame + ) -> t.Tuple[Frame, MacroRef]: + """Dump the function def of a macro or call block.""" + frame = frame.inner() + frame.symbols.analyze_node(node) + macro_ref = MacroRef(node) + + explicit_caller = None + skip_special_params = set() + args = [] + + for idx, arg in enumerate(node.args): + if arg.name == "caller": + explicit_caller = idx + if arg.name in ("kwargs", "varargs"): + skip_special_params.add(arg.name) + args.append(frame.symbols.ref(arg.name)) + + undeclared = find_undeclared(node.body, ("caller", "kwargs", "varargs")) + + if "caller" in undeclared: + # In older Jinja versions there was a bug that allowed caller + # to retain the special behavior even if it was mentioned in + # the argument list. However thankfully this was only really + # working if it was the last argument. So we are explicitly + # checking this now and error out if it is anywhere else in + # the argument list. + if explicit_caller is not None: + try: + node.defaults[explicit_caller - len(node.args)] + except IndexError: + self.fail( + "When defining macros or call blocks the " + 'special "caller" argument must be omitted ' + "or be given a default.", + node.lineno, + ) + else: + args.append(frame.symbols.declare_parameter("caller")) + macro_ref.accesses_caller = True + if "kwargs" in undeclared and "kwargs" not in skip_special_params: + args.append(frame.symbols.declare_parameter("kwargs")) + macro_ref.accesses_kwargs = True + if "varargs" in undeclared and "varargs" not in skip_special_params: + args.append(frame.symbols.declare_parameter("varargs")) + macro_ref.accesses_varargs = True + + # macros are delayed, they never require output checks + frame.require_output_check = False + frame.symbols.analyze_node(node) + self.writeline(f"{self.func('macro')}({', '.join(args)}):", node) + self.indent() + + self.buffer(frame) + self.enter_frame(frame) + + self.push_parameter_definitions(frame) + for idx, arg in enumerate(node.args): + ref = frame.symbols.ref(arg.name) + self.writeline(f"if {ref} is missing:") + self.indent() + try: + default = node.defaults[idx - len(node.args)] + except IndexError: + self.writeline( + f'{ref} = undefined("parameter {arg.name!r} was not provided",' + f" name={arg.name!r})" + ) + else: + self.writeline(f"{ref} = ") + self.visit(default, frame) + self.mark_parameter_stored(ref) + self.outdent() + self.pop_parameter_definitions() + + self.blockvisit(node.body, frame) + self.return_buffer_contents(frame, force_unescaped=True) + self.leave_frame(frame, with_python_scope=True) + self.outdent() + + return frame, macro_ref + + def macro_def(self, macro_ref: MacroRef, frame: Frame) -> None: + """Dump the macro definition for the def created by macro_body.""" + arg_tuple = ", ".join(repr(x.name) for x in macro_ref.node.args) + name = getattr(macro_ref.node, "name", None) + if len(macro_ref.node.args) == 1: + arg_tuple += "," + self.write( + f"Macro(environment, macro, {name!r}, ({arg_tuple})," + f" {macro_ref.accesses_kwargs!r}, {macro_ref.accesses_varargs!r}," + f" {macro_ref.accesses_caller!r}, context.eval_ctx.autoescape)" + ) + + def position(self, node: nodes.Node) -> str: + """Return a human readable position for the node.""" + rv = f"line {node.lineno}" + if self.name is not None: + rv = f"{rv} in {self.name!r}" + return rv + + def dump_local_context(self, frame: Frame) -> str: + items_kv = ", ".join( + f"{name!r}: {target}" + for name, target in frame.symbols.dump_stores().items() + ) + return f"{{{items_kv}}}" + + def write_commons(self) -> None: + """Writes a common preamble that is used by root and block functions. + Primarily this sets up common local helpers and enforces a generator + through a dead branch. + """ + self.writeline("resolve = context.resolve_or_missing") + self.writeline("undefined = environment.undefined") + self.writeline("concat = environment.concat") + # always use the standard Undefined class for the implicit else of + # conditional expressions + self.writeline("cond_expr_undefined = Undefined") + self.writeline("if 0: yield None") + + def push_parameter_definitions(self, frame: Frame) -> None: + """Pushes all parameter targets from the given frame into a local + stack that permits tracking of yet to be assigned parameters. In + particular this enables the optimization from `visit_Name` to skip + undefined expressions for parameters in macros as macros can reference + otherwise unbound parameters. + """ + self._param_def_block.append(frame.symbols.dump_param_targets()) + + def pop_parameter_definitions(self) -> None: + """Pops the current parameter definitions set.""" + self._param_def_block.pop() + + def mark_parameter_stored(self, target: str) -> None: + """Marks a parameter in the current parameter definitions as stored. + This will skip the enforced undefined checks. + """ + if self._param_def_block: + self._param_def_block[-1].discard(target) + + def push_context_reference(self, target: str) -> None: + self._context_reference_stack.append(target) + + def pop_context_reference(self) -> None: + self._context_reference_stack.pop() + + def get_context_ref(self) -> str: + return self._context_reference_stack[-1] + + def get_resolve_func(self) -> str: + target = self._context_reference_stack[-1] + if target == "context": + return "resolve" + return f"{target}.resolve" + + def derive_context(self, frame: Frame) -> str: + return f"{self.get_context_ref()}.derived({self.dump_local_context(frame)})" + + def parameter_is_undeclared(self, target: str) -> bool: + """Checks if a given target is an undeclared parameter.""" + if not self._param_def_block: + return False + return target in self._param_def_block[-1] + + def push_assign_tracking(self) -> None: + """Pushes a new layer for assignment tracking.""" + self._assign_stack.append(set()) + + def pop_assign_tracking(self, frame: Frame) -> None: + """Pops the topmost level for assignment tracking and updates the + context variables if necessary. + """ + vars = self._assign_stack.pop() + if ( + not frame.block_frame + and not frame.loop_frame + and not frame.toplevel + or not vars + ): + return + public_names = [x for x in vars if x[:1] != "_"] + if len(vars) == 1: + name = next(iter(vars)) + ref = frame.symbols.ref(name) + if frame.loop_frame: + self.writeline(f"_loop_vars[{name!r}] = {ref}") + return + if frame.block_frame: + self.writeline(f"_block_vars[{name!r}] = {ref}") + return + self.writeline(f"context.vars[{name!r}] = {ref}") + else: + if frame.loop_frame: + self.writeline("_loop_vars.update({") + elif frame.block_frame: + self.writeline("_block_vars.update({") + else: + self.writeline("context.vars.update({") + for idx, name in enumerate(vars): + if idx: + self.write(", ") + ref = frame.symbols.ref(name) + self.write(f"{name!r}: {ref}") + self.write("})") + if not frame.block_frame and not frame.loop_frame and public_names: + if len(public_names) == 1: + self.writeline(f"context.exported_vars.add({public_names[0]!r})") + else: + names_str = ", ".join(map(repr, public_names)) + self.writeline(f"context.exported_vars.update(({names_str}))") + + # -- Statement Visitors + + def visit_Template( + self, node: nodes.Template, frame: t.Optional[Frame] = None + ) -> None: + assert frame is None, "no root frame allowed" + eval_ctx = EvalContext(self.environment, self.name) + + from .runtime import exported, async_exported + + if self.environment.is_async: + exported_names = sorted(exported + async_exported) + else: + exported_names = sorted(exported) + + self.writeline("from jinja2.runtime import " + ", ".join(exported_names)) + + # if we want a deferred initialization we cannot move the + # environment into a local name + envenv = "" if self.defer_init else ", environment=environment" + + # do we have an extends tag at all? If not, we can save some + # overhead by just not processing any inheritance code. + have_extends = node.find(nodes.Extends) is not None + + # find all blocks + for block in node.find_all(nodes.Block): + if block.name in self.blocks: + self.fail(f"block {block.name!r} defined twice", block.lineno) + self.blocks[block.name] = block + + # find all imports and import them + for import_ in node.find_all(nodes.ImportedName): + if import_.importname not in self.import_aliases: + imp = import_.importname + self.import_aliases[imp] = alias = self.temporary_identifier() + if "." in imp: + module, obj = imp.rsplit(".", 1) + self.writeline(f"from {module} import {obj} as {alias}") + else: + self.writeline(f"import {imp} as {alias}") + + # add the load name + self.writeline(f"name = {self.name!r}") + + # generate the root render function. + self.writeline( + f"{self.func('root')}(context, missing=missing{envenv}):", extra=1 + ) + self.indent() + self.write_commons() + + # process the root + frame = Frame(eval_ctx) + if "self" in find_undeclared(node.body, ("self",)): + ref = frame.symbols.declare_parameter("self") + self.writeline(f"{ref} = TemplateReference(context)") + frame.symbols.analyze_node(node) + frame.toplevel = frame.rootlevel = True + frame.require_output_check = have_extends and not self.has_known_extends + if have_extends: + self.writeline("parent_template = None") + self.enter_frame(frame) + self.pull_dependencies(node.body) + self.blockvisit(node.body, frame) + self.leave_frame(frame, with_python_scope=True) + self.outdent() + + # make sure that the parent root is called. + if have_extends: + if not self.has_known_extends: + self.indent() + self.writeline("if parent_template is not None:") + self.indent() + if not self.environment.is_async: + self.writeline("yield from parent_template.root_render_func(context)") + else: + self.writeline( + "async for event in parent_template.root_render_func(context):" + ) + self.indent() + self.writeline("yield event") + self.outdent() + self.outdent(1 + (not self.has_known_extends)) + + # at this point we now have the blocks collected and can visit them too. + for name, block in self.blocks.items(): + self.writeline( + f"{self.func('block_' + name)}(context, missing=missing{envenv}):", + block, + 1, + ) + self.indent() + self.write_commons() + # It's important that we do not make this frame a child of the + # toplevel template. This would cause a variety of + # interesting issues with identifier tracking. + block_frame = Frame(eval_ctx) + block_frame.block_frame = True + undeclared = find_undeclared(block.body, ("self", "super")) + if "self" in undeclared: + ref = block_frame.symbols.declare_parameter("self") + self.writeline(f"{ref} = TemplateReference(context)") + if "super" in undeclared: + ref = block_frame.symbols.declare_parameter("super") + self.writeline(f"{ref} = context.super({name!r}, block_{name})") + block_frame.symbols.analyze_node(block) + block_frame.block = name + self.writeline("_block_vars = {}") + self.enter_frame(block_frame) + self.pull_dependencies(block.body) + self.blockvisit(block.body, block_frame) + self.leave_frame(block_frame, with_python_scope=True) + self.outdent() + + blocks_kv_str = ", ".join(f"{x!r}: block_{x}" for x in self.blocks) + self.writeline(f"blocks = {{{blocks_kv_str}}}", extra=1) + debug_kv_str = "&".join(f"{k}={v}" for k, v in self.debug_info) + self.writeline(f"debug_info = {debug_kv_str!r}") + + def visit_Block(self, node: nodes.Block, frame: Frame) -> None: + """Call a block and register it for the template.""" + level = 0 + if frame.toplevel: + # if we know that we are a child template, there is no need to + # check if we are one + if self.has_known_extends: + return + if self.extends_so_far > 0: + self.writeline("if parent_template is None:") + self.indent() + level += 1 + + if node.scoped: + context = self.derive_context(frame) + else: + context = self.get_context_ref() + + if node.required: + self.writeline(f"if len(context.blocks[{node.name!r}]) <= 1:", node) + self.indent() + self.writeline( + f'raise TemplateRuntimeError("Required block {node.name!r} not found")', + node, + ) + self.outdent() + + if not self.environment.is_async and frame.buffer is None: + self.writeline( + f"yield from context.blocks[{node.name!r}][0]({context})", node + ) + else: + self.writeline( + f"{self.choose_async()}for event in" + f" context.blocks[{node.name!r}][0]({context}):", + node, + ) + self.indent() + self.simple_write("event", frame) + self.outdent() + + self.outdent(level) + + def visit_Extends(self, node: nodes.Extends, frame: Frame) -> None: + """Calls the extender.""" + if not frame.toplevel: + self.fail("cannot use extend from a non top-level scope", node.lineno) + + # if the number of extends statements in general is zero so + # far, we don't have to add a check if something extended + # the template before this one. + if self.extends_so_far > 0: + + # if we have a known extends we just add a template runtime + # error into the generated code. We could catch that at compile + # time too, but i welcome it not to confuse users by throwing the + # same error at different times just "because we can". + if not self.has_known_extends: + self.writeline("if parent_template is not None:") + self.indent() + self.writeline('raise TemplateRuntimeError("extended multiple times")') + + # if we have a known extends already we don't need that code here + # as we know that the template execution will end here. + if self.has_known_extends: + raise CompilerExit() + else: + self.outdent() + + self.writeline("parent_template = environment.get_template(", node) + self.visit(node.template, frame) + self.write(f", {self.name!r})") + self.writeline("for name, parent_block in parent_template.blocks.items():") + self.indent() + self.writeline("context.blocks.setdefault(name, []).append(parent_block)") + self.outdent() + + # if this extends statement was in the root level we can take + # advantage of that information and simplify the generated code + # in the top level from this point onwards + if frame.rootlevel: + self.has_known_extends = True + + # and now we have one more + self.extends_so_far += 1 + + def visit_Include(self, node: nodes.Include, frame: Frame) -> None: + """Handles includes.""" + if node.ignore_missing: + self.writeline("try:") + self.indent() + + func_name = "get_or_select_template" + if isinstance(node.template, nodes.Const): + if isinstance(node.template.value, str): + func_name = "get_template" + elif isinstance(node.template.value, (tuple, list)): + func_name = "select_template" + elif isinstance(node.template, (nodes.Tuple, nodes.List)): + func_name = "select_template" + + self.writeline(f"template = environment.{func_name}(", node) + self.visit(node.template, frame) + self.write(f", {self.name!r})") + if node.ignore_missing: + self.outdent() + self.writeline("except TemplateNotFound:") + self.indent() + self.writeline("pass") + self.outdent() + self.writeline("else:") + self.indent() + + skip_event_yield = False + if node.with_context: + self.writeline( + f"{self.choose_async()}for event in template.root_render_func(" + "template.new_context(context.get_all(), True," + f" {self.dump_local_context(frame)})):" + ) + elif self.environment.is_async: + self.writeline( + "for event in (await template._get_default_module_async())" + "._body_stream:" + ) + else: + self.writeline("yield from template._get_default_module()._body_stream") + skip_event_yield = True + + if not skip_event_yield: + self.indent() + self.simple_write("event", frame) + self.outdent() + + if node.ignore_missing: + self.outdent() + + def _import_common( + self, node: t.Union[nodes.Import, nodes.FromImport], frame: Frame + ) -> None: + self.write(f"{self.choose_async('await ')}environment.get_template(") + self.visit(node.template, frame) + self.write(f", {self.name!r}).") + + if node.with_context: + f_name = f"make_module{self.choose_async('_async')}" + self.write( + f"{f_name}(context.get_all(), True, {self.dump_local_context(frame)})" + ) + else: + self.write(f"_get_default_module{self.choose_async('_async')}(context)") + + def visit_Import(self, node: nodes.Import, frame: Frame) -> None: + """Visit regular imports.""" + self.writeline(f"{frame.symbols.ref(node.target)} = ", node) + if frame.toplevel: + self.write(f"context.vars[{node.target!r}] = ") + + self._import_common(node, frame) + + if frame.toplevel and not node.target.startswith("_"): + self.writeline(f"context.exported_vars.discard({node.target!r})") + + def visit_FromImport(self, node: nodes.FromImport, frame: Frame) -> None: + """Visit named imports.""" + self.newline(node) + self.write("included_template = ") + self._import_common(node, frame) + var_names = [] + discarded_names = [] + for name in node.names: + if isinstance(name, tuple): + name, alias = name + else: + alias = name + self.writeline( + f"{frame.symbols.ref(alias)} =" + f" getattr(included_template, {name!r}, missing)" + ) + self.writeline(f"if {frame.symbols.ref(alias)} is missing:") + self.indent() + message = ( + "the template {included_template.__name__!r}" + f" (imported on {self.position(node)})" + f" does not export the requested name {name!r}" + ) + self.writeline( + f"{frame.symbols.ref(alias)} = undefined(f{message!r}, name={name!r})" + ) + self.outdent() + if frame.toplevel: + var_names.append(alias) + if not alias.startswith("_"): + discarded_names.append(alias) + + if var_names: + if len(var_names) == 1: + name = var_names[0] + self.writeline(f"context.vars[{name!r}] = {frame.symbols.ref(name)}") + else: + names_kv = ", ".join( + f"{name!r}: {frame.symbols.ref(name)}" for name in var_names + ) + self.writeline(f"context.vars.update({{{names_kv}}})") + if discarded_names: + if len(discarded_names) == 1: + self.writeline(f"context.exported_vars.discard({discarded_names[0]!r})") + else: + names_str = ", ".join(map(repr, discarded_names)) + self.writeline( + f"context.exported_vars.difference_update(({names_str}))" + ) + + def visit_For(self, node: nodes.For, frame: Frame) -> None: + loop_frame = frame.inner() + loop_frame.loop_frame = True + test_frame = frame.inner() + else_frame = frame.inner() + + # try to figure out if we have an extended loop. An extended loop + # is necessary if the loop is in recursive mode if the special loop + # variable is accessed in the body if the body is a scoped block. + extended_loop = ( + node.recursive + or "loop" + in find_undeclared(node.iter_child_nodes(only=("body",)), ("loop",)) + or any(block.scoped for block in node.find_all(nodes.Block)) + ) + + loop_ref = None + if extended_loop: + loop_ref = loop_frame.symbols.declare_parameter("loop") + + loop_frame.symbols.analyze_node(node, for_branch="body") + if node.else_: + else_frame.symbols.analyze_node(node, for_branch="else") + + if node.test: + loop_filter_func = self.temporary_identifier() + test_frame.symbols.analyze_node(node, for_branch="test") + self.writeline(f"{self.func(loop_filter_func)}(fiter):", node.test) + self.indent() + self.enter_frame(test_frame) + self.writeline(self.choose_async("async for ", "for ")) + self.visit(node.target, loop_frame) + self.write(" in ") + self.write(self.choose_async("auto_aiter(fiter)", "fiter")) + self.write(":") + self.indent() + self.writeline("if ", node.test) + self.visit(node.test, test_frame) + self.write(":") + self.indent() + self.writeline("yield ") + self.visit(node.target, loop_frame) + self.outdent(3) + self.leave_frame(test_frame, with_python_scope=True) + + # if we don't have an recursive loop we have to find the shadowed + # variables at that point. Because loops can be nested but the loop + # variable is a special one we have to enforce aliasing for it. + if node.recursive: + self.writeline( + f"{self.func('loop')}(reciter, loop_render_func, depth=0):", node + ) + self.indent() + self.buffer(loop_frame) + + # Use the same buffer for the else frame + else_frame.buffer = loop_frame.buffer + + # make sure the loop variable is a special one and raise a template + # assertion error if a loop tries to write to loop + if extended_loop: + self.writeline(f"{loop_ref} = missing") + + for name in node.find_all(nodes.Name): + if name.ctx == "store" and name.name == "loop": + self.fail( + "Can't assign to special loop variable in for-loop target", + name.lineno, + ) + + if node.else_: + iteration_indicator = self.temporary_identifier() + self.writeline(f"{iteration_indicator} = 1") + + self.writeline(self.choose_async("async for ", "for "), node) + self.visit(node.target, loop_frame) + if extended_loop: + self.write(f", {loop_ref} in {self.choose_async('Async')}LoopContext(") + else: + self.write(" in ") + + if node.test: + self.write(f"{loop_filter_func}(") + if node.recursive: + self.write("reciter") + else: + if self.environment.is_async and not extended_loop: + self.write("auto_aiter(") + self.visit(node.iter, frame) + if self.environment.is_async and not extended_loop: + self.write(")") + if node.test: + self.write(")") + + if node.recursive: + self.write(", undefined, loop_render_func, depth):") + else: + self.write(", undefined):" if extended_loop else ":") + + self.indent() + self.enter_frame(loop_frame) + + self.writeline("_loop_vars = {}") + self.blockvisit(node.body, loop_frame) + if node.else_: + self.writeline(f"{iteration_indicator} = 0") + self.outdent() + self.leave_frame( + loop_frame, with_python_scope=node.recursive and not node.else_ + ) + + if node.else_: + self.writeline(f"if {iteration_indicator}:") + self.indent() + self.enter_frame(else_frame) + self.blockvisit(node.else_, else_frame) + self.leave_frame(else_frame) + self.outdent() + + # if the node was recursive we have to return the buffer contents + # and start the iteration code + if node.recursive: + self.return_buffer_contents(loop_frame) + self.outdent() + self.start_write(frame, node) + self.write(f"{self.choose_async('await ')}loop(") + if self.environment.is_async: + self.write("auto_aiter(") + self.visit(node.iter, frame) + if self.environment.is_async: + self.write(")") + self.write(", loop)") + self.end_write(frame) + + # at the end of the iteration, clear any assignments made in the + # loop from the top level + if self._assign_stack: + self._assign_stack[-1].difference_update(loop_frame.symbols.stores) + + def visit_If(self, node: nodes.If, frame: Frame) -> None: + if_frame = frame.soft() + self.writeline("if ", node) + self.visit(node.test, if_frame) + self.write(":") + self.indent() + self.blockvisit(node.body, if_frame) + self.outdent() + for elif_ in node.elif_: + self.writeline("elif ", elif_) + self.visit(elif_.test, if_frame) + self.write(":") + self.indent() + self.blockvisit(elif_.body, if_frame) + self.outdent() + if node.else_: + self.writeline("else:") + self.indent() + self.blockvisit(node.else_, if_frame) + self.outdent() + + def visit_Macro(self, node: nodes.Macro, frame: Frame) -> None: + macro_frame, macro_ref = self.macro_body(node, frame) + self.newline() + if frame.toplevel: + if not node.name.startswith("_"): + self.write(f"context.exported_vars.add({node.name!r})") + self.writeline(f"context.vars[{node.name!r}] = ") + self.write(f"{frame.symbols.ref(node.name)} = ") + self.macro_def(macro_ref, macro_frame) + + def visit_CallBlock(self, node: nodes.CallBlock, frame: Frame) -> None: + call_frame, macro_ref = self.macro_body(node, frame) + self.writeline("caller = ") + self.macro_def(macro_ref, call_frame) + self.start_write(frame, node) + self.visit_Call(node.call, frame, forward_caller=True) + self.end_write(frame) + + def visit_FilterBlock(self, node: nodes.FilterBlock, frame: Frame) -> None: + filter_frame = frame.inner() + filter_frame.symbols.analyze_node(node) + self.enter_frame(filter_frame) + self.buffer(filter_frame) + self.blockvisit(node.body, filter_frame) + self.start_write(frame, node) + self.visit_Filter(node.filter, filter_frame) + self.end_write(frame) + self.leave_frame(filter_frame) + + def visit_With(self, node: nodes.With, frame: Frame) -> None: + with_frame = frame.inner() + with_frame.symbols.analyze_node(node) + self.enter_frame(with_frame) + for target, expr in zip(node.targets, node.values): + self.newline() + self.visit(target, with_frame) + self.write(" = ") + self.visit(expr, frame) + self.blockvisit(node.body, with_frame) + self.leave_frame(with_frame) + + def visit_ExprStmt(self, node: nodes.ExprStmt, frame: Frame) -> None: + self.newline(node) + self.visit(node.node, frame) + + class _FinalizeInfo(t.NamedTuple): + const: t.Optional[t.Callable[..., str]] + src: t.Optional[str] + + @staticmethod + def _default_finalize(value: t.Any) -> t.Any: + """The default finalize function if the environment isn't + configured with one. Or, if the environment has one, this is + called on that function's output for constants. + """ + return str(value) + + _finalize: t.Optional[_FinalizeInfo] = None + + def _make_finalize(self) -> _FinalizeInfo: + """Build the finalize function to be used on constants and at + runtime. Cached so it's only created once for all output nodes. + + Returns a ``namedtuple`` with the following attributes: + + ``const`` + A function to finalize constant data at compile time. + + ``src`` + Source code to output around nodes to be evaluated at + runtime. + """ + if self._finalize is not None: + return self._finalize + + finalize: t.Optional[t.Callable[..., t.Any]] + finalize = default = self._default_finalize + src = None + + if self.environment.finalize: + src = "environment.finalize(" + env_finalize = self.environment.finalize + pass_arg = { + _PassArg.context: "context", + _PassArg.eval_context: "context.eval_ctx", + _PassArg.environment: "environment", + }.get( + _PassArg.from_obj(env_finalize) # type: ignore + ) + finalize = None + + if pass_arg is None: + + def finalize(value: t.Any) -> t.Any: + return default(env_finalize(value)) + + else: + src = f"{src}{pass_arg}, " + + if pass_arg == "environment": + + def finalize(value: t.Any) -> t.Any: + return default(env_finalize(self.environment, value)) + + self._finalize = self._FinalizeInfo(finalize, src) + return self._finalize + + def _output_const_repr(self, group: t.Iterable[t.Any]) -> str: + """Given a group of constant values converted from ``Output`` + child nodes, produce a string to write to the template module + source. + """ + return repr(concat(group)) + + def _output_child_to_const( + self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo + ) -> str: + """Try to optimize a child of an ``Output`` node by trying to + convert it to constant, finalized data at compile time. + + If :exc:`Impossible` is raised, the node is not constant and + will be evaluated at runtime. Any other exception will also be + evaluated at runtime for easier debugging. + """ + const = node.as_const(frame.eval_ctx) + + if frame.eval_ctx.autoescape: + const = escape(const) + + # Template data doesn't go through finalize. + if isinstance(node, nodes.TemplateData): + return str(const) + + return finalize.const(const) # type: ignore + + def _output_child_pre( + self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo + ) -> None: + """Output extra source code before visiting a child of an + ``Output`` node. + """ + if frame.eval_ctx.volatile: + self.write("(escape if context.eval_ctx.autoescape else str)(") + elif frame.eval_ctx.autoescape: + self.write("escape(") + else: + self.write("str(") + + if finalize.src is not None: + self.write(finalize.src) + + def _output_child_post( + self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo + ) -> None: + """Output extra source code after visiting a child of an + ``Output`` node. + """ + self.write(")") + + if finalize.src is not None: + self.write(")") + + def visit_Output(self, node: nodes.Output, frame: Frame) -> None: + # If an extends is active, don't render outside a block. + if frame.require_output_check: + # A top-level extends is known to exist at compile time. + if self.has_known_extends: + return + + self.writeline("if parent_template is None:") + self.indent() + + finalize = self._make_finalize() + body: t.List[t.Union[t.List[t.Any], nodes.Expr]] = [] + + # Evaluate constants at compile time if possible. Each item in + # body will be either a list of static data or a node to be + # evaluated at runtime. + for child in node.nodes: + try: + if not ( + # If the finalize function requires runtime context, + # constants can't be evaluated at compile time. + finalize.const + # Unless it's basic template data that won't be + # finalized anyway. + or isinstance(child, nodes.TemplateData) + ): + raise nodes.Impossible() + + const = self._output_child_to_const(child, frame, finalize) + except (nodes.Impossible, Exception): + # The node was not constant and needs to be evaluated at + # runtime. Or another error was raised, which is easier + # to debug at runtime. + body.append(child) + continue + + if body and isinstance(body[-1], list): + body[-1].append(const) + else: + body.append([const]) + + if frame.buffer is not None: + if len(body) == 1: + self.writeline(f"{frame.buffer}.append(") + else: + self.writeline(f"{frame.buffer}.extend((") + + self.indent() + + for item in body: + if isinstance(item, list): + # A group of constant data to join and output. + val = self._output_const_repr(item) + + if frame.buffer is None: + self.writeline("yield " + val) + else: + self.writeline(val + ",") + else: + if frame.buffer is None: + self.writeline("yield ", item) + else: + self.newline(item) + + # A node to be evaluated at runtime. + self._output_child_pre(item, frame, finalize) + self.visit(item, frame) + self._output_child_post(item, frame, finalize) + + if frame.buffer is not None: + self.write(",") + + if frame.buffer is not None: + self.outdent() + self.writeline(")" if len(body) == 1 else "))") + + if frame.require_output_check: + self.outdent() + + def visit_Assign(self, node: nodes.Assign, frame: Frame) -> None: + self.push_assign_tracking() + self.newline(node) + self.visit(node.target, frame) + self.write(" = ") + self.visit(node.node, frame) + self.pop_assign_tracking(frame) + + def visit_AssignBlock(self, node: nodes.AssignBlock, frame: Frame) -> None: + self.push_assign_tracking() + block_frame = frame.inner() + # This is a special case. Since a set block always captures we + # will disable output checks. This way one can use set blocks + # toplevel even in extended templates. + block_frame.require_output_check = False + block_frame.symbols.analyze_node(node) + self.enter_frame(block_frame) + self.buffer(block_frame) + self.blockvisit(node.body, block_frame) + self.newline(node) + self.visit(node.target, frame) + self.write(" = (Markup if context.eval_ctx.autoescape else identity)(") + if node.filter is not None: + self.visit_Filter(node.filter, block_frame) + else: + self.write(f"concat({block_frame.buffer})") + self.write(")") + self.pop_assign_tracking(frame) + self.leave_frame(block_frame) + + # -- Expression Visitors + + def visit_Name(self, node: nodes.Name, frame: Frame) -> None: + if node.ctx == "store" and ( + frame.toplevel or frame.loop_frame or frame.block_frame + ): + if self._assign_stack: + self._assign_stack[-1].add(node.name) + ref = frame.symbols.ref(node.name) + + # If we are looking up a variable we might have to deal with the + # case where it's undefined. We can skip that case if the load + # instruction indicates a parameter which are always defined. + if node.ctx == "load": + load = frame.symbols.find_load(ref) + if not ( + load is not None + and load[0] == VAR_LOAD_PARAMETER + and not self.parameter_is_undeclared(ref) + ): + self.write( + f"(undefined(name={node.name!r}) if {ref} is missing else {ref})" + ) + return + + self.write(ref) + + def visit_NSRef(self, node: nodes.NSRef, frame: Frame) -> None: + # NSRefs can only be used to store values; since they use the normal + # `foo.bar` notation they will be parsed as a normal attribute access + # when used anywhere but in a `set` context + ref = frame.symbols.ref(node.name) + self.writeline(f"if not isinstance({ref}, Namespace):") + self.indent() + self.writeline( + "raise TemplateRuntimeError" + '("cannot assign attribute on non-namespace object")' + ) + self.outdent() + self.writeline(f"{ref}[{node.attr!r}]") + + def visit_Const(self, node: nodes.Const, frame: Frame) -> None: + val = node.as_const(frame.eval_ctx) + if isinstance(val, float): + self.write(str(val)) + else: + self.write(repr(val)) + + def visit_TemplateData(self, node: nodes.TemplateData, frame: Frame) -> None: + try: + self.write(repr(node.as_const(frame.eval_ctx))) + except nodes.Impossible: + self.write( + f"(Markup if context.eval_ctx.autoescape else identity)({node.data!r})" + ) + + def visit_Tuple(self, node: nodes.Tuple, frame: Frame) -> None: + self.write("(") + idx = -1 + for idx, item in enumerate(node.items): + if idx: + self.write(", ") + self.visit(item, frame) + self.write(",)" if idx == 0 else ")") + + def visit_List(self, node: nodes.List, frame: Frame) -> None: + self.write("[") + for idx, item in enumerate(node.items): + if idx: + self.write(", ") + self.visit(item, frame) + self.write("]") + + def visit_Dict(self, node: nodes.Dict, frame: Frame) -> None: + self.write("{") + for idx, item in enumerate(node.items): + if idx: + self.write(", ") + self.visit(item.key, frame) + self.write(": ") + self.visit(item.value, frame) + self.write("}") + + visit_Add = _make_binop("+") + visit_Sub = _make_binop("-") + visit_Mul = _make_binop("*") + visit_Div = _make_binop("/") + visit_FloorDiv = _make_binop("//") + visit_Pow = _make_binop("**") + visit_Mod = _make_binop("%") + visit_And = _make_binop("and") + visit_Or = _make_binop("or") + visit_Pos = _make_unop("+") + visit_Neg = _make_unop("-") + visit_Not = _make_unop("not ") + + @optimizeconst + def visit_Concat(self, node: nodes.Concat, frame: Frame) -> None: + if frame.eval_ctx.volatile: + func_name = "(markup_join if context.eval_ctx.volatile else str_join)" + elif frame.eval_ctx.autoescape: + func_name = "markup_join" + else: + func_name = "str_join" + self.write(f"{func_name}((") + for arg in node.nodes: + self.visit(arg, frame) + self.write(", ") + self.write("))") + + @optimizeconst + def visit_Compare(self, node: nodes.Compare, frame: Frame) -> None: + self.write("(") + self.visit(node.expr, frame) + for op in node.ops: + self.visit(op, frame) + self.write(")") + + def visit_Operand(self, node: nodes.Operand, frame: Frame) -> None: + self.write(f" {operators[node.op]} ") + self.visit(node.expr, frame) + + @optimizeconst + def visit_Getattr(self, node: nodes.Getattr, frame: Frame) -> None: + if self.environment.is_async: + self.write("(await auto_await(") + + self.write("environment.getattr(") + self.visit(node.node, frame) + self.write(f", {node.attr!r})") + + if self.environment.is_async: + self.write("))") + + @optimizeconst + def visit_Getitem(self, node: nodes.Getitem, frame: Frame) -> None: + # slices bypass the environment getitem method. + if isinstance(node.arg, nodes.Slice): + self.visit(node.node, frame) + self.write("[") + self.visit(node.arg, frame) + self.write("]") + else: + if self.environment.is_async: + self.write("(await auto_await(") + + self.write("environment.getitem(") + self.visit(node.node, frame) + self.write(", ") + self.visit(node.arg, frame) + self.write(")") + + if self.environment.is_async: + self.write("))") + + def visit_Slice(self, node: nodes.Slice, frame: Frame) -> None: + if node.start is not None: + self.visit(node.start, frame) + self.write(":") + if node.stop is not None: + self.visit(node.stop, frame) + if node.step is not None: + self.write(":") + self.visit(node.step, frame) + + @contextmanager + def _filter_test_common( + self, node: t.Union[nodes.Filter, nodes.Test], frame: Frame, is_filter: bool + ) -> t.Iterator[None]: + if self.environment.is_async: + self.write("(await auto_await(") + + if is_filter: + self.write(f"{self.filters[node.name]}(") + func = self.environment.filters.get(node.name) + else: + self.write(f"{self.tests[node.name]}(") + func = self.environment.tests.get(node.name) + + # When inside an If or CondExpr frame, allow the filter to be + # undefined at compile time and only raise an error if it's + # actually called at runtime. See pull_dependencies. + if func is None and not frame.soft_frame: + type_name = "filter" if is_filter else "test" + self.fail(f"No {type_name} named {node.name!r}.", node.lineno) + + pass_arg = { + _PassArg.context: "context", + _PassArg.eval_context: "context.eval_ctx", + _PassArg.environment: "environment", + }.get( + _PassArg.from_obj(func) # type: ignore + ) + + if pass_arg is not None: + self.write(f"{pass_arg}, ") + + # Back to the visitor function to handle visiting the target of + # the filter or test. + yield + + self.signature(node, frame) + self.write(")") + + if self.environment.is_async: + self.write("))") + + @optimizeconst + def visit_Filter(self, node: nodes.Filter, frame: Frame) -> None: + with self._filter_test_common(node, frame, True): + # if the filter node is None we are inside a filter block + # and want to write to the current buffer + if node.node is not None: + self.visit(node.node, frame) + elif frame.eval_ctx.volatile: + self.write( + f"(Markup(concat({frame.buffer}))" + f" if context.eval_ctx.autoescape else concat({frame.buffer}))" + ) + elif frame.eval_ctx.autoescape: + self.write(f"Markup(concat({frame.buffer}))") + else: + self.write(f"concat({frame.buffer})") + + @optimizeconst + def visit_Test(self, node: nodes.Test, frame: Frame) -> None: + with self._filter_test_common(node, frame, False): + self.visit(node.node, frame) + + @optimizeconst + def visit_CondExpr(self, node: nodes.CondExpr, frame: Frame) -> None: + frame = frame.soft() + + def write_expr2() -> None: + if node.expr2 is not None: + self.visit(node.expr2, frame) + return + + self.write( + f'cond_expr_undefined("the inline if-expression on' + f" {self.position(node)} evaluated to false and no else" + f' section was defined.")' + ) + + self.write("(") + self.visit(node.expr1, frame) + self.write(" if ") + self.visit(node.test, frame) + self.write(" else ") + write_expr2() + self.write(")") + + @optimizeconst + def visit_Call( + self, node: nodes.Call, frame: Frame, forward_caller: bool = False + ) -> None: + if self.environment.is_async: + self.write("(await auto_await(") + if self.environment.sandboxed: + self.write("environment.call(context, ") + else: + self.write("context.call(") + self.visit(node.node, frame) + extra_kwargs = {"caller": "caller"} if forward_caller else None + loop_kwargs = {"_loop_vars": "_loop_vars"} if frame.loop_frame else {} + block_kwargs = {"_block_vars": "_block_vars"} if frame.block_frame else {} + if extra_kwargs: + extra_kwargs.update(loop_kwargs, **block_kwargs) + elif loop_kwargs or block_kwargs: + extra_kwargs = dict(loop_kwargs, **block_kwargs) + self.signature(node, frame, extra_kwargs) + self.write(")") + if self.environment.is_async: + self.write("))") + + def visit_Keyword(self, node: nodes.Keyword, frame: Frame) -> None: + self.write(node.key + "=") + self.visit(node.value, frame) + + # -- Unused nodes for extensions + + def visit_MarkSafe(self, node: nodes.MarkSafe, frame: Frame) -> None: + self.write("Markup(") + self.visit(node.expr, frame) + self.write(")") + + def visit_MarkSafeIfAutoescape( + self, node: nodes.MarkSafeIfAutoescape, frame: Frame + ) -> None: + self.write("(Markup if context.eval_ctx.autoescape else identity)(") + self.visit(node.expr, frame) + self.write(")") + + def visit_EnvironmentAttribute( + self, node: nodes.EnvironmentAttribute, frame: Frame + ) -> None: + self.write("environment." + node.name) + + def visit_ExtensionAttribute( + self, node: nodes.ExtensionAttribute, frame: Frame + ) -> None: + self.write(f"environment.extensions[{node.identifier!r}].{node.name}") + + def visit_ImportedName(self, node: nodes.ImportedName, frame: Frame) -> None: + self.write(self.import_aliases[node.importname]) + + def visit_InternalName(self, node: nodes.InternalName, frame: Frame) -> None: + self.write(node.name) + + def visit_ContextReference( + self, node: nodes.ContextReference, frame: Frame + ) -> None: + self.write("context") + + def visit_DerivedContextReference( + self, node: nodes.DerivedContextReference, frame: Frame + ) -> None: + self.write(self.derive_context(frame)) + + def visit_Continue(self, node: nodes.Continue, frame: Frame) -> None: + self.writeline("continue", node) + + def visit_Break(self, node: nodes.Break, frame: Frame) -> None: + self.writeline("break", node) + + def visit_Scope(self, node: nodes.Scope, frame: Frame) -> None: + scope_frame = frame.inner() + scope_frame.symbols.analyze_node(node) + self.enter_frame(scope_frame) + self.blockvisit(node.body, scope_frame) + self.leave_frame(scope_frame) + + def visit_OverlayScope(self, node: nodes.OverlayScope, frame: Frame) -> None: + ctx = self.temporary_identifier() + self.writeline(f"{ctx} = {self.derive_context(frame)}") + self.writeline(f"{ctx}.vars = ") + self.visit(node.context, frame) + self.push_context_reference(ctx) + + scope_frame = frame.inner(isolated=True) + scope_frame.symbols.analyze_node(node) + self.enter_frame(scope_frame) + self.blockvisit(node.body, scope_frame) + self.leave_frame(scope_frame) + self.pop_context_reference() + + def visit_EvalContextModifier( + self, node: nodes.EvalContextModifier, frame: Frame + ) -> None: + for keyword in node.options: + self.writeline(f"context.eval_ctx.{keyword.key} = ") + self.visit(keyword.value, frame) + try: + val = keyword.value.as_const(frame.eval_ctx) + except nodes.Impossible: + frame.eval_ctx.volatile = True + else: + setattr(frame.eval_ctx, keyword.key, val) + + def visit_ScopedEvalContextModifier( + self, node: nodes.ScopedEvalContextModifier, frame: Frame + ) -> None: + old_ctx_name = self.temporary_identifier() + saved_ctx = frame.eval_ctx.save() + self.writeline(f"{old_ctx_name} = context.eval_ctx.save()") + self.visit_EvalContextModifier(node, frame) + for child in node.body: + self.visit(child, frame) + frame.eval_ctx.revert(saved_ctx) + self.writeline(f"context.eval_ctx.revert({old_ctx_name})") diff --git a/.venv/Lib/site-packages/jinja2/constants.py b/.venv/Lib/site-packages/jinja2/constants.py new file mode 100644 index 000000000..41a1c23b0 --- /dev/null +++ b/.venv/Lib/site-packages/jinja2/constants.py @@ -0,0 +1,20 @@ +#: list of lorem ipsum words used by the lipsum() helper function +LOREM_IPSUM_WORDS = """\ +a ac accumsan ad adipiscing aenean aliquam aliquet amet ante aptent arcu at +auctor augue bibendum blandit class commodo condimentum congue consectetuer +consequat conubia convallis cras cubilia cum curabitur curae cursus dapibus +diam dictum dictumst dignissim dis dolor donec dui duis egestas eget eleifend +elementum elit enim erat eros est et etiam eu euismod facilisi facilisis fames +faucibus felis fermentum feugiat fringilla fusce gravida habitant habitasse hac +hendrerit hymenaeos iaculis id imperdiet in inceptos integer interdum ipsum +justo lacinia lacus laoreet lectus leo libero ligula litora lobortis lorem +luctus maecenas magna magnis malesuada massa mattis mauris metus mi molestie +mollis montes morbi mus nam nascetur natoque nec neque netus nibh nisi nisl non +nonummy nostra nulla nullam nunc odio orci ornare parturient pede pellentesque +penatibus per pharetra phasellus placerat platea porta porttitor posuere +potenti praesent pretium primis proin pulvinar purus quam quis quisque rhoncus +ridiculus risus rutrum sagittis sapien scelerisque sed sem semper senectus sit +sociis sociosqu sodales sollicitudin suscipit suspendisse taciti tellus tempor +tempus tincidunt torquent tortor tristique turpis ullamcorper ultrices +ultricies urna ut varius vehicula vel velit venenatis vestibulum vitae vivamus +viverra volutpat vulputate""" diff --git a/.venv/Lib/site-packages/jinja2/debug.py b/.venv/Lib/site-packages/jinja2/debug.py new file mode 100644 index 000000000..7ed7e9297 --- /dev/null +++ b/.venv/Lib/site-packages/jinja2/debug.py @@ -0,0 +1,191 @@ +import sys +import typing as t +from types import CodeType +from types import TracebackType + +from .exceptions import TemplateSyntaxError +from .utils import internal_code +from .utils import missing + +if t.TYPE_CHECKING: + from .runtime import Context + + +def rewrite_traceback_stack(source: t.Optional[str] = None) -> BaseException: + """Rewrite the current exception to replace any tracebacks from + within compiled template code with tracebacks that look like they + came from the template source. + + This must be called within an ``except`` block. + + :param source: For ``TemplateSyntaxError``, the original source if + known. + :return: The original exception with the rewritten traceback. + """ + _, exc_value, tb = sys.exc_info() + exc_value = t.cast(BaseException, exc_value) + tb = t.cast(TracebackType, tb) + + if isinstance(exc_value, TemplateSyntaxError) and not exc_value.translated: + exc_value.translated = True + exc_value.source = source + # Remove the old traceback, otherwise the frames from the + # compiler still show up. + exc_value.with_traceback(None) + # Outside of runtime, so the frame isn't executing template + # code, but it still needs to point at the template. + tb = fake_traceback( + exc_value, None, exc_value.filename or "", exc_value.lineno + ) + else: + # Skip the frame for the render function. + tb = tb.tb_next + + stack = [] + + # Build the stack of traceback object, replacing any in template + # code with the source file and line information. + while tb is not None: + # Skip frames decorated with @internalcode. These are internal + # calls that aren't useful in template debugging output. + if tb.tb_frame.f_code in internal_code: + tb = tb.tb_next + continue + + template = tb.tb_frame.f_globals.get("__jinja_template__") + + if template is not None: + lineno = template.get_corresponding_lineno(tb.tb_lineno) + fake_tb = fake_traceback(exc_value, tb, template.filename, lineno) + stack.append(fake_tb) + else: + stack.append(tb) + + tb = tb.tb_next + + tb_next = None + + # Assign tb_next in reverse to avoid circular references. + for tb in reversed(stack): + tb.tb_next = tb_next + tb_next = tb + + return exc_value.with_traceback(tb_next) + + +def fake_traceback( # type: ignore + exc_value: BaseException, tb: t.Optional[TracebackType], filename: str, lineno: int +) -> TracebackType: + """Produce a new traceback object that looks like it came from the + template source instead of the compiled code. The filename, line + number, and location name will point to the template, and the local + variables will be the current template context. + + :param exc_value: The original exception to be re-raised to create + the new traceback. + :param tb: The original traceback to get the local variables and + code info from. + :param filename: The template filename. + :param lineno: The line number in the template source. + """ + if tb is not None: + # Replace the real locals with the context that would be + # available at that point in the template. + locals = get_template_locals(tb.tb_frame.f_locals) + locals.pop("__jinja_exception__", None) + else: + locals = {} + + globals = { + "__name__": filename, + "__file__": filename, + "__jinja_exception__": exc_value, + } + # Raise an exception at the correct line number. + code: CodeType = compile( + "\n" * (lineno - 1) + "raise __jinja_exception__", filename, "exec" + ) + + # Build a new code object that points to the template file and + # replaces the location with a block name. + location = "template" + + if tb is not None: + function = tb.tb_frame.f_code.co_name + + if function == "root": + location = "top-level template code" + elif function.startswith("block_"): + location = f"block {function[6:]!r}" + + if sys.version_info >= (3, 8): + code = code.replace(co_name=location) + else: + code = CodeType( + code.co_argcount, + code.co_kwonlyargcount, + code.co_nlocals, + code.co_stacksize, + code.co_flags, + code.co_code, + code.co_consts, + code.co_names, + code.co_varnames, + code.co_filename, + location, + code.co_firstlineno, + code.co_lnotab, + code.co_freevars, + code.co_cellvars, + ) + + # Execute the new code, which is guaranteed to raise, and return + # the new traceback without this frame. + try: + exec(code, globals, locals) + except BaseException: + return sys.exc_info()[2].tb_next # type: ignore + + +def get_template_locals(real_locals: t.Mapping[str, t.Any]) -> t.Dict[str, t.Any]: + """Based on the runtime locals, get the context that would be + available at that point in the template. + """ + # Start with the current template context. + ctx: "t.Optional[Context]" = real_locals.get("context") + + if ctx is not None: + data: t.Dict[str, t.Any] = ctx.get_all().copy() + else: + data = {} + + # Might be in a derived context that only sets local variables + # rather than pushing a context. Local variables follow the scheme + # l_depth_name. Find the highest-depth local that has a value for + # each name. + local_overrides: t.Dict[str, t.Tuple[int, t.Any]] = {} + + for name, value in real_locals.items(): + if not name.startswith("l_") or value is missing: + # Not a template variable, or no longer relevant. + continue + + try: + _, depth_str, name = name.split("_", 2) + depth = int(depth_str) + except ValueError: + continue + + cur_depth = local_overrides.get(name, (-1,))[0] + + if cur_depth < depth: + local_overrides[name] = (depth, value) + + # Modify the context with any derived context. + for name, (_, value) in local_overrides.items(): + if value is missing: + data.pop(name, None) + else: + data[name] = value + + return data diff --git a/.venv/Lib/site-packages/jinja2/defaults.py b/.venv/Lib/site-packages/jinja2/defaults.py new file mode 100644 index 000000000..638cad3d2 --- /dev/null +++ b/.venv/Lib/site-packages/jinja2/defaults.py @@ -0,0 +1,48 @@ +import typing as t + +from .filters import FILTERS as DEFAULT_FILTERS # noqa: F401 +from .tests import TESTS as DEFAULT_TESTS # noqa: F401 +from .utils import Cycler +from .utils import generate_lorem_ipsum +from .utils import Joiner +from .utils import Namespace + +if t.TYPE_CHECKING: + import typing_extensions as te + +# defaults for the parser / lexer +BLOCK_START_STRING = "{%" +BLOCK_END_STRING = "%}" +VARIABLE_START_STRING = "{{" +VARIABLE_END_STRING = "}}" +COMMENT_START_STRING = "{#" +COMMENT_END_STRING = "#}" +LINE_STATEMENT_PREFIX: t.Optional[str] = None +LINE_COMMENT_PREFIX: t.Optional[str] = None +TRIM_BLOCKS = False +LSTRIP_BLOCKS = False +NEWLINE_SEQUENCE: "te.Literal['\\n', '\\r\\n', '\\r']" = "\n" +KEEP_TRAILING_NEWLINE = False + +# default filters, tests and namespace + +DEFAULT_NAMESPACE = { + "range": range, + "dict": dict, + "lipsum": generate_lorem_ipsum, + "cycler": Cycler, + "joiner": Joiner, + "namespace": Namespace, +} + +# default policies +DEFAULT_POLICIES: t.Dict[str, t.Any] = { + "compiler.ascii_str": True, + "urlize.rel": "noopener", + "urlize.target": None, + "urlize.extra_schemes": None, + "truncate.leeway": 5, + "json.dumps_function": None, + "json.dumps_kwargs": {"sort_keys": True}, + "ext.i18n.trimmed": False, +} diff --git a/.venv/Lib/site-packages/jinja2/environment.py b/.venv/Lib/site-packages/jinja2/environment.py new file mode 100644 index 000000000..ea04e8b44 --- /dev/null +++ b/.venv/Lib/site-packages/jinja2/environment.py @@ -0,0 +1,1667 @@ +"""Classes for managing templates and their runtime and compile time +options. +""" +import os +import typing +import typing as t +import weakref +from collections import ChainMap +from functools import lru_cache +from functools import partial +from functools import reduce +from types import CodeType + +from markupsafe import Markup + +from . import nodes +from .compiler import CodeGenerator +from .compiler import generate +from .defaults import BLOCK_END_STRING +from .defaults import BLOCK_START_STRING +from .defaults import COMMENT_END_STRING +from .defaults import COMMENT_START_STRING +from .defaults import DEFAULT_FILTERS +from .defaults import DEFAULT_NAMESPACE +from .defaults import DEFAULT_POLICIES +from .defaults import DEFAULT_TESTS +from .defaults import KEEP_TRAILING_NEWLINE +from .defaults import LINE_COMMENT_PREFIX +from .defaults import LINE_STATEMENT_PREFIX +from .defaults import LSTRIP_BLOCKS +from .defaults import NEWLINE_SEQUENCE +from .defaults import TRIM_BLOCKS +from .defaults import VARIABLE_END_STRING +from .defaults import VARIABLE_START_STRING +from .exceptions import TemplateNotFound +from .exceptions import TemplateRuntimeError +from .exceptions import TemplatesNotFound +from .exceptions import TemplateSyntaxError +from .exceptions import UndefinedError +from .lexer import get_lexer +from .lexer import Lexer +from .lexer import TokenStream +from .nodes import EvalContext +from .parser import Parser +from .runtime import Context +from .runtime import new_context +from .runtime import Undefined +from .utils import _PassArg +from .utils import concat +from .utils import consume +from .utils import import_string +from .utils import internalcode +from .utils import LRUCache +from .utils import missing + +if t.TYPE_CHECKING: + import typing_extensions as te + from .bccache import BytecodeCache + from .ext import Extension + from .loaders import BaseLoader + +_env_bound = t.TypeVar("_env_bound", bound="Environment") + + +# for direct template usage we have up to ten living environments +@lru_cache(maxsize=10) +def get_spontaneous_environment(cls: t.Type[_env_bound], *args: t.Any) -> _env_bound: + """Return a new spontaneous environment. A spontaneous environment + is used for templates created directly rather than through an + existing environment. + + :param cls: Environment class to create. + :param args: Positional arguments passed to environment. + """ + env = cls(*args) + env.shared = True + return env + + +def create_cache( + size: int, +) -> t.Optional[t.MutableMapping[t.Tuple[weakref.ref, str], "Template"]]: + """Return the cache class for the given size.""" + if size == 0: + return None + + if size < 0: + return {} + + return LRUCache(size) # type: ignore + + +def copy_cache( + cache: t.Optional[t.MutableMapping], +) -> t.Optional[t.MutableMapping[t.Tuple[weakref.ref, str], "Template"]]: + """Create an empty copy of the given cache.""" + if cache is None: + return None + + if type(cache) is dict: + return {} + + return LRUCache(cache.capacity) # type: ignore + + +def load_extensions( + environment: "Environment", + extensions: t.Sequence[t.Union[str, t.Type["Extension"]]], +) -> t.Dict[str, "Extension"]: + """Load the extensions from the list and bind it to the environment. + Returns a dict of instantiated extensions. + """ + result = {} + + for extension in extensions: + if isinstance(extension, str): + extension = t.cast(t.Type["Extension"], import_string(extension)) + + result[extension.identifier] = extension(environment) + + return result + + +def _environment_config_check(environment: "Environment") -> "Environment": + """Perform a sanity check on the environment.""" + assert issubclass( + environment.undefined, Undefined + ), "'undefined' must be a subclass of 'jinja2.Undefined'." + assert ( + environment.block_start_string + != environment.variable_start_string + != environment.comment_start_string + ), "block, variable and comment start strings must be different." + assert environment.newline_sequence in { + "\r", + "\r\n", + "\n", + }, "'newline_sequence' must be one of '\\n', '\\r\\n', or '\\r'." + return environment + + +class Environment: + r"""The core component of Jinja is the `Environment`. It contains + important shared variables like configuration, filters, tests, + globals and others. Instances of this class may be modified if + they are not shared and if no template was loaded so far. + Modifications on environments after the first template was loaded + will lead to surprising effects and undefined behavior. + + Here are the possible initialization parameters: + + `block_start_string` + The string marking the beginning of a block. Defaults to ``'{%'``. + + `block_end_string` + The string marking the end of a block. Defaults to ``'%}'``. + + `variable_start_string` + The string marking the beginning of a print statement. + Defaults to ``'{{'``. + + `variable_end_string` + The string marking the end of a print statement. Defaults to + ``'}}'``. + + `comment_start_string` + The string marking the beginning of a comment. Defaults to ``'{#'``. + + `comment_end_string` + The string marking the end of a comment. Defaults to ``'#}'``. + + `line_statement_prefix` + If given and a string, this will be used as prefix for line based + statements. See also :ref:`line-statements`. + + `line_comment_prefix` + If given and a string, this will be used as prefix for line based + comments. See also :ref:`line-statements`. + + .. versionadded:: 2.2 + + `trim_blocks` + If this is set to ``True`` the first newline after a block is + removed (block, not variable tag!). Defaults to `False`. + + `lstrip_blocks` + If this is set to ``True`` leading spaces and tabs are stripped + from the start of a line to a block. Defaults to `False`. + + `newline_sequence` + The sequence that starts a newline. Must be one of ``'\r'``, + ``'\n'`` or ``'\r\n'``. The default is ``'\n'`` which is a + useful default for Linux and OS X systems as well as web + applications. + + `keep_trailing_newline` + Preserve the trailing newline when rendering templates. + The default is ``False``, which causes a single newline, + if present, to be stripped from the end of the template. + + .. versionadded:: 2.7 + + `extensions` + List of Jinja extensions to use. This can either be import paths + as strings or extension classes. For more information have a + look at :ref:`the extensions documentation `. + + `optimized` + should the optimizer be enabled? Default is ``True``. + + `undefined` + :class:`Undefined` or a subclass of it that is used to represent + undefined values in the template. + + `finalize` + A callable that can be used to process the result of a variable + expression before it is output. For example one can convert + ``None`` implicitly into an empty string here. + + `autoescape` + If set to ``True`` the XML/HTML autoescaping feature is enabled by + default. For more details about autoescaping see + :class:`~markupsafe.Markup`. As of Jinja 2.4 this can also + be a callable that is passed the template name and has to + return ``True`` or ``False`` depending on autoescape should be + enabled by default. + + .. versionchanged:: 2.4 + `autoescape` can now be a function + + `loader` + The template loader for this environment. + + `cache_size` + The size of the cache. Per default this is ``400`` which means + that if more than 400 templates are loaded the loader will clean + out the least recently used template. If the cache size is set to + ``0`` templates are recompiled all the time, if the cache size is + ``-1`` the cache will not be cleaned. + + .. versionchanged:: 2.8 + The cache size was increased to 400 from a low 50. + + `auto_reload` + Some loaders load templates from locations where the template + sources may change (ie: file system or database). If + ``auto_reload`` is set to ``True`` (default) every time a template is + requested the loader checks if the source changed and if yes, it + will reload the template. For higher performance it's possible to + disable that. + + `bytecode_cache` + If set to a bytecode cache object, this object will provide a + cache for the internal Jinja bytecode so that templates don't + have to be parsed if they were not changed. + + See :ref:`bytecode-cache` for more information. + + `enable_async` + If set to true this enables async template execution which + allows using async functions and generators. + """ + + #: if this environment is sandboxed. Modifying this variable won't make + #: the environment sandboxed though. For a real sandboxed environment + #: have a look at jinja2.sandbox. This flag alone controls the code + #: generation by the compiler. + sandboxed = False + + #: True if the environment is just an overlay + overlayed = False + + #: the environment this environment is linked to if it is an overlay + linked_to: t.Optional["Environment"] = None + + #: shared environments have this set to `True`. A shared environment + #: must not be modified + shared = False + + #: the class that is used for code generation. See + #: :class:`~jinja2.compiler.CodeGenerator` for more information. + code_generator_class: t.Type["CodeGenerator"] = CodeGenerator + + concat = "".join + + #: the context class that is used for templates. See + #: :class:`~jinja2.runtime.Context` for more information. + context_class: t.Type[Context] = Context + + template_class: t.Type["Template"] + + def __init__( + self, + block_start_string: str = BLOCK_START_STRING, + block_end_string: str = BLOCK_END_STRING, + variable_start_string: str = VARIABLE_START_STRING, + variable_end_string: str = VARIABLE_END_STRING, + comment_start_string: str = COMMENT_START_STRING, + comment_end_string: str = COMMENT_END_STRING, + line_statement_prefix: t.Optional[str] = LINE_STATEMENT_PREFIX, + line_comment_prefix: t.Optional[str] = LINE_COMMENT_PREFIX, + trim_blocks: bool = TRIM_BLOCKS, + lstrip_blocks: bool = LSTRIP_BLOCKS, + newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = NEWLINE_SEQUENCE, + keep_trailing_newline: bool = KEEP_TRAILING_NEWLINE, + extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = (), + optimized: bool = True, + undefined: t.Type[Undefined] = Undefined, + finalize: t.Optional[t.Callable[..., t.Any]] = None, + autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False, + loader: t.Optional["BaseLoader"] = None, + cache_size: int = 400, + auto_reload: bool = True, + bytecode_cache: t.Optional["BytecodeCache"] = None, + enable_async: bool = False, + ): + # !!Important notice!! + # The constructor accepts quite a few arguments that should be + # passed by keyword rather than position. However it's important to + # not change the order of arguments because it's used at least + # internally in those cases: + # - spontaneous environments (i18n extension and Template) + # - unittests + # If parameter changes are required only add parameters at the end + # and don't change the arguments (or the defaults!) of the arguments + # existing already. + + # lexer / parser information + self.block_start_string = block_start_string + self.block_end_string = block_end_string + self.variable_start_string = variable_start_string + self.variable_end_string = variable_end_string + self.comment_start_string = comment_start_string + self.comment_end_string = comment_end_string + self.line_statement_prefix = line_statement_prefix + self.line_comment_prefix = line_comment_prefix + self.trim_blocks = trim_blocks + self.lstrip_blocks = lstrip_blocks + self.newline_sequence = newline_sequence + self.keep_trailing_newline = keep_trailing_newline + + # runtime information + self.undefined: t.Type[Undefined] = undefined + self.optimized = optimized + self.finalize = finalize + self.autoescape = autoescape + + # defaults + self.filters = DEFAULT_FILTERS.copy() + self.tests = DEFAULT_TESTS.copy() + self.globals = DEFAULT_NAMESPACE.copy() + + # set the loader provided + self.loader = loader + self.cache = create_cache(cache_size) + self.bytecode_cache = bytecode_cache + self.auto_reload = auto_reload + + # configurable policies + self.policies = DEFAULT_POLICIES.copy() + + # load extensions + self.extensions = load_extensions(self, extensions) + + self.is_async = enable_async + _environment_config_check(self) + + def add_extension(self, extension: t.Union[str, t.Type["Extension"]]) -> None: + """Adds an extension after the environment was created. + + .. versionadded:: 2.5 + """ + self.extensions.update(load_extensions(self, [extension])) + + def extend(self, **attributes: t.Any) -> None: + """Add the items to the instance of the environment if they do not exist + yet. This is used by :ref:`extensions ` to register + callbacks and configuration values without breaking inheritance. + """ + for key, value in attributes.items(): + if not hasattr(self, key): + setattr(self, key, value) + + def overlay( + self, + block_start_string: str = missing, + block_end_string: str = missing, + variable_start_string: str = missing, + variable_end_string: str = missing, + comment_start_string: str = missing, + comment_end_string: str = missing, + line_statement_prefix: t.Optional[str] = missing, + line_comment_prefix: t.Optional[str] = missing, + trim_blocks: bool = missing, + lstrip_blocks: bool = missing, + newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = missing, + keep_trailing_newline: bool = missing, + extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = missing, + optimized: bool = missing, + undefined: t.Type[Undefined] = missing, + finalize: t.Optional[t.Callable[..., t.Any]] = missing, + autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = missing, + loader: t.Optional["BaseLoader"] = missing, + cache_size: int = missing, + auto_reload: bool = missing, + bytecode_cache: t.Optional["BytecodeCache"] = missing, + enable_async: bool = False, + ) -> "Environment": + """Create a new overlay environment that shares all the data with the + current environment except for cache and the overridden attributes. + Extensions cannot be removed for an overlayed environment. An overlayed + environment automatically gets all the extensions of the environment it + is linked to plus optional extra extensions. + + Creating overlays should happen after the initial environment was set + up completely. Not all attributes are truly linked, some are just + copied over so modifications on the original environment may not shine + through. + + .. versionchanged:: 3.1.2 + Added the ``newline_sequence``,, ``keep_trailing_newline``, + and ``enable_async`` parameters to match ``__init__``. + """ + args = dict(locals()) + del args["self"], args["cache_size"], args["extensions"], args["enable_async"] + + rv = object.__new__(self.__class__) + rv.__dict__.update(self.__dict__) + rv.overlayed = True + rv.linked_to = self + + for key, value in args.items(): + if value is not missing: + setattr(rv, key, value) + + if cache_size is not missing: + rv.cache = create_cache(cache_size) + else: + rv.cache = copy_cache(self.cache) + + rv.extensions = {} + for key, value in self.extensions.items(): + rv.extensions[key] = value.bind(rv) + if extensions is not missing: + rv.extensions.update(load_extensions(rv, extensions)) + + if enable_async is not missing: + rv.is_async = enable_async + + return _environment_config_check(rv) + + @property + def lexer(self) -> Lexer: + """The lexer for this environment.""" + return get_lexer(self) + + def iter_extensions(self) -> t.Iterator["Extension"]: + """Iterates over the extensions by priority.""" + return iter(sorted(self.extensions.values(), key=lambda x: x.priority)) + + def getitem( + self, obj: t.Any, argument: t.Union[str, t.Any] + ) -> t.Union[t.Any, Undefined]: + """Get an item or attribute of an object but prefer the item.""" + try: + return obj[argument] + except (AttributeError, TypeError, LookupError): + if isinstance(argument, str): + try: + attr = str(argument) + except Exception: + pass + else: + try: + return getattr(obj, attr) + except AttributeError: + pass + return self.undefined(obj=obj, name=argument) + + def getattr(self, obj: t.Any, attribute: str) -> t.Any: + """Get an item or attribute of an object but prefer the attribute. + Unlike :meth:`getitem` the attribute *must* be a string. + """ + try: + return getattr(obj, attribute) + except AttributeError: + pass + try: + return obj[attribute] + except (TypeError, LookupError, AttributeError): + return self.undefined(obj=obj, name=attribute) + + def _filter_test_common( + self, + name: t.Union[str, Undefined], + value: t.Any, + args: t.Optional[t.Sequence[t.Any]], + kwargs: t.Optional[t.Mapping[str, t.Any]], + context: t.Optional[Context], + eval_ctx: t.Optional[EvalContext], + is_filter: bool, + ) -> t.Any: + if is_filter: + env_map = self.filters + type_name = "filter" + else: + env_map = self.tests + type_name = "test" + + func = env_map.get(name) # type: ignore + + if func is None: + msg = f"No {type_name} named {name!r}." + + if isinstance(name, Undefined): + try: + name._fail_with_undefined_error() + except Exception as e: + msg = f"{msg} ({e}; did you forget to quote the callable name?)" + + raise TemplateRuntimeError(msg) + + args = [value, *(args if args is not None else ())] + kwargs = kwargs if kwargs is not None else {} + pass_arg = _PassArg.from_obj(func) + + if pass_arg is _PassArg.context: + if context is None: + raise TemplateRuntimeError( + f"Attempted to invoke a context {type_name} without context." + ) + + args.insert(0, context) + elif pass_arg is _PassArg.eval_context: + if eval_ctx is None: + if context is not None: + eval_ctx = context.eval_ctx + else: + eval_ctx = EvalContext(self) + + args.insert(0, eval_ctx) + elif pass_arg is _PassArg.environment: + args.insert(0, self) + + return func(*args, **kwargs) + + def call_filter( + self, + name: str, + value: t.Any, + args: t.Optional[t.Sequence[t.Any]] = None, + kwargs: t.Optional[t.Mapping[str, t.Any]] = None, + context: t.Optional[Context] = None, + eval_ctx: t.Optional[EvalContext] = None, + ) -> t.Any: + """Invoke a filter on a value the same way the compiler does. + + This might return a coroutine if the filter is running from an + environment in async mode and the filter supports async + execution. It's your responsibility to await this if needed. + + .. versionadded:: 2.7 + """ + return self._filter_test_common( + name, value, args, kwargs, context, eval_ctx, True + ) + + def call_test( + self, + name: str, + value: t.Any, + args: t.Optional[t.Sequence[t.Any]] = None, + kwargs: t.Optional[t.Mapping[str, t.Any]] = None, + context: t.Optional[Context] = None, + eval_ctx: t.Optional[EvalContext] = None, + ) -> t.Any: + """Invoke a test on a value the same way the compiler does. + + This might return a coroutine if the test is running from an + environment in async mode and the test supports async execution. + It's your responsibility to await this if needed. + + .. versionchanged:: 3.0 + Tests support ``@pass_context``, etc. decorators. Added + the ``context`` and ``eval_ctx`` parameters. + + .. versionadded:: 2.7 + """ + return self._filter_test_common( + name, value, args, kwargs, context, eval_ctx, False + ) + + @internalcode + def parse( + self, + source: str, + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + ) -> nodes.Template: + """Parse the sourcecode and return the abstract syntax tree. This + tree of nodes is used by the compiler to convert the template into + executable source- or bytecode. This is useful for debugging or to + extract information from templates. + + If you are :ref:`developing Jinja extensions ` + this gives you a good overview of the node tree generated. + """ + try: + return self._parse(source, name, filename) + except TemplateSyntaxError: + self.handle_exception(source=source) + + def _parse( + self, source: str, name: t.Optional[str], filename: t.Optional[str] + ) -> nodes.Template: + """Internal parsing function used by `parse` and `compile`.""" + return Parser(self, source, name, filename).parse() + + def lex( + self, + source: str, + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + ) -> t.Iterator[t.Tuple[int, str, str]]: + """Lex the given sourcecode and return a generator that yields + tokens as tuples in the form ``(lineno, token_type, value)``. + This can be useful for :ref:`extension development ` + and debugging templates. + + This does not perform preprocessing. If you want the preprocessing + of the extensions to be applied you have to filter source through + the :meth:`preprocess` method. + """ + source = str(source) + try: + return self.lexer.tokeniter(source, name, filename) + except TemplateSyntaxError: + self.handle_exception(source=source) + + def preprocess( + self, + source: str, + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + ) -> str: + """Preprocesses the source with all extensions. This is automatically + called for all parsing and compiling methods but *not* for :meth:`lex` + because there you usually only want the actual source tokenized. + """ + return reduce( + lambda s, e: e.preprocess(s, name, filename), + self.iter_extensions(), + str(source), + ) + + def _tokenize( + self, + source: str, + name: t.Optional[str], + filename: t.Optional[str] = None, + state: t.Optional[str] = None, + ) -> TokenStream: + """Called by the parser to do the preprocessing and filtering + for all the extensions. Returns a :class:`~jinja2.lexer.TokenStream`. + """ + source = self.preprocess(source, name, filename) + stream = self.lexer.tokenize(source, name, filename, state) + + for ext in self.iter_extensions(): + stream = ext.filter_stream(stream) # type: ignore + + if not isinstance(stream, TokenStream): + stream = TokenStream(stream, name, filename) # type: ignore + + return stream + + def _generate( + self, + source: nodes.Template, + name: t.Optional[str], + filename: t.Optional[str], + defer_init: bool = False, + ) -> str: + """Internal hook that can be overridden to hook a different generate + method in. + + .. versionadded:: 2.5 + """ + return generate( # type: ignore + source, + self, + name, + filename, + defer_init=defer_init, + optimized=self.optimized, + ) + + def _compile(self, source: str, filename: str) -> CodeType: + """Internal hook that can be overridden to hook a different compile + method in. + + .. versionadded:: 2.5 + """ + return compile(source, filename, "exec") # type: ignore + + @typing.overload + def compile( # type: ignore + self, + source: t.Union[str, nodes.Template], + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + raw: "te.Literal[False]" = False, + defer_init: bool = False, + ) -> CodeType: + ... + + @typing.overload + def compile( + self, + source: t.Union[str, nodes.Template], + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + raw: "te.Literal[True]" = ..., + defer_init: bool = False, + ) -> str: + ... + + @internalcode + def compile( + self, + source: t.Union[str, nodes.Template], + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + raw: bool = False, + defer_init: bool = False, + ) -> t.Union[str, CodeType]: + """Compile a node or template source code. The `name` parameter is + the load name of the template after it was joined using + :meth:`join_path` if necessary, not the filename on the file system. + the `filename` parameter is the estimated filename of the template on + the file system. If the template came from a database or memory this + can be omitted. + + The return value of this method is a python code object. If the `raw` + parameter is `True` the return value will be a string with python + code equivalent to the bytecode returned otherwise. This method is + mainly used internally. + + `defer_init` is use internally to aid the module code generator. This + causes the generated code to be able to import without the global + environment variable to be set. + + .. versionadded:: 2.4 + `defer_init` parameter added. + """ + source_hint = None + try: + if isinstance(source, str): + source_hint = source + source = self._parse(source, name, filename) + source = self._generate(source, name, filename, defer_init=defer_init) + if raw: + return source + if filename is None: + filename = "

;6@Lti4qS+$D|IpouPbZbeL;OvJ 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 F{}0^<8?FEV literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/constants.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/constants.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a88ebd4d0653b41620630dd124d532e4d906ca00 GIT binary patch literal 1569 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 O@1J+bRq0JQihltndHX^D literal 0 HcmV?d00001 diff --git a/.venv/Lib/site-packages/jinja2/__pycache__/environment.cpython-311.pyc b/.venv/Lib/site-packages/jinja2/__pycache__/environment.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8d56aa82ba6d81f3b663ad1811bb1bbd048e09af GIT binary patch literal 80551 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 z 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