From 04073cb2f05c81e0b2f11ff58e9189c664d722f2 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 21 Jul 2026 17:19:34 +0900 Subject: [PATCH] Remove server/venv from git tracking (too large, should use requirements.txt) --- .../_mysql_connector.cp313-win_amd64.pyd | Bin 72880 -> 0 bytes .../venv/Lib/site-packages/_yaml/__init__.py | 33 - .../annotated_doc-0.0.4.dist-info/INSTALLER | 1 - .../annotated_doc-0.0.4.dist-info/METADATA | 145 - .../annotated_doc-0.0.4.dist-info/RECORD | 11 - .../annotated_doc-0.0.4.dist-info/WHEEL | 4 - .../entry_points.txt | 4 - .../licenses/LICENSE | 21 - .../site-packages/annotated_doc/__init__.py | 3 - .../Lib/site-packages/annotated_doc/main.py | 36 - .../Lib/site-packages/annotated_doc/py.typed | 0 .../annotated_types-0.7.0.dist-info/INSTALLER | 1 - .../annotated_types-0.7.0.dist-info/METADATA | 295 - .../annotated_types-0.7.0.dist-info/RECORD | 10 - .../annotated_types-0.7.0.dist-info/WHEEL | 4 - .../licenses/LICENSE | 21 - .../site-packages/annotated_types/__init__.py | 432 - .../site-packages/annotated_types/py.typed | 0 .../annotated_types/test_cases.py | 151 - .../anyio-4.14.0.dist-info/INSTALLER | 1 - .../anyio-4.14.0.dist-info/METADATA | 107 - .../anyio-4.14.0.dist-info/RECORD | 94 - .../anyio-4.14.0.dist-info/WHEEL | 5 - .../anyio-4.14.0.dist-info/entry_points.txt | 2 - .../anyio-4.14.0.dist-info/licenses/LICENSE | 20 - .../anyio-4.14.0.dist-info/top_level.txt | 1 - .../venv/Lib/site-packages/anyio/__init__.py | 115 - .../site-packages/anyio/_backends/__init__.py | 0 .../site-packages/anyio/_backends/_asyncio.py | 3073 --- .../site-packages/anyio/_backends/_trio.py | 1456 -- .../Lib/site-packages/anyio/_core/__init__.py | 0 .../anyio/_core/_asyncio_selector_thread.py | 167 - .../anyio/_core/_contextmanagers.py | 200 - .../site-packages/anyio/_core/_eventloop.py | 240 - .../site-packages/anyio/_core/_exceptions.py | 177 - .../Lib/site-packages/anyio/_core/_fileio.py | 960 - .../site-packages/anyio/_core/_resources.py | 18 - .../Lib/site-packages/anyio/_core/_signals.py | 29 - .../Lib/site-packages/anyio/_core/_sockets.py | 1011 - .../Lib/site-packages/anyio/_core/_streams.py | 52 - .../anyio/_core/_subprocesses.py | 196 - .../anyio/_core/_synchronization.py | 772 - .../Lib/site-packages/anyio/_core/_tasks.py | 415 - .../site-packages/anyio/_core/_tempfile.py | 613 - .../Lib/site-packages/anyio/_core/_testing.py | 82 - .../site-packages/anyio/_core/_typedattr.py | 81 - .../Lib/site-packages/anyio/abc/__init__.py | 58 - .../Lib/site-packages/anyio/abc/_eventloop.py | 410 - .../Lib/site-packages/anyio/abc/_resources.py | 33 - .../Lib/site-packages/anyio/abc/_sockets.py | 399 - .../Lib/site-packages/anyio/abc/_streams.py | 233 - .../site-packages/anyio/abc/_subprocesses.py | 79 - .../Lib/site-packages/anyio/abc/_tasks.py | 209 - .../Lib/site-packages/anyio/abc/_testing.py | 73 - .../Lib/site-packages/anyio/from_thread.py | 582 - .../venv/Lib/site-packages/anyio/functools.py | 400 - .../venv/Lib/site-packages/anyio/itertools.py | 626 - .../venv/Lib/site-packages/anyio/lowlevel.py | 226 - server/venv/Lib/site-packages/anyio/py.typed | 0 .../Lib/site-packages/anyio/pytest_plugin.py | 375 - .../site-packages/anyio/streams/__init__.py | 0 .../site-packages/anyio/streams/buffered.py | 198 - .../Lib/site-packages/anyio/streams/file.py | 154 - .../Lib/site-packages/anyio/streams/memory.py | 325 - .../site-packages/anyio/streams/stapled.py | 147 - .../Lib/site-packages/anyio/streams/text.py | 176 - .../Lib/site-packages/anyio/streams/tls.py | 421 - .../Lib/site-packages/anyio/to_interpreter.py | 246 - .../Lib/site-packages/anyio/to_process.py | 268 - .../venv/Lib/site-packages/anyio/to_thread.py | 78 - .../click-8.4.1.dist-info/INSTALLER | 1 - .../click-8.4.1.dist-info/METADATA | 84 - .../click-8.4.1.dist-info/RECORD | 40 - .../site-packages/click-8.4.1.dist-info/WHEEL | 4 - .../licenses/LICENSE.txt | 28 - .../venv/Lib/site-packages/click/__init__.py | 126 - .../venv/Lib/site-packages/click/_compat.py | 627 - .../Lib/site-packages/click/_termui_impl.py | 929 - .../venv/Lib/site-packages/click/_textwrap.py | 188 - server/venv/Lib/site-packages/click/_utils.py | 36 - .../Lib/site-packages/click/_winconsole.py | 297 - server/venv/Lib/site-packages/click/core.py | 3542 ---- .../Lib/site-packages/click/decorators.py | 551 - .../Lib/site-packages/click/exceptions.py | 347 - .../Lib/site-packages/click/formatting.py | 315 - .../venv/Lib/site-packages/click/globals.py | 67 - server/venv/Lib/site-packages/click/parser.py | 533 - server/venv/Lib/site-packages/click/py.typed | 0 .../site-packages/click/shell_completion.py | 680 - server/venv/Lib/site-packages/click/termui.py | 941 - .../venv/Lib/site-packages/click/testing.py | 736 - server/venv/Lib/site-packages/click/types.py | 1309 -- server/venv/Lib/site-packages/click/utils.py | 641 - .../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 - .../Lib/site-packages/colorama/__init__.py | 7 - .../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 - .../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 - .../Lib/site-packages/colorama/winterm.py | 195 - server/venv/Lib/site-packages/comerr64.dll | Bin 31360 -> 0 bytes .../venv/Lib/site-packages/dotenv/__init__.py | 51 - .../venv/Lib/site-packages/dotenv/__main__.py | 6 - server/venv/Lib/site-packages/dotenv/cli.py | 236 - .../venv/Lib/site-packages/dotenv/ipython.py | 50 - server/venv/Lib/site-packages/dotenv/main.py | 480 - .../venv/Lib/site-packages/dotenv/parser.py | 182 - server/venv/Lib/site-packages/dotenv/py.typed | 1 - .../Lib/site-packages/dotenv/variables.py | 86 - .../venv/Lib/site-packages/dotenv/version.py | 1 - .../fastapi-0.138.0.dist-info/INSTALLER | 1 - .../fastapi-0.138.0.dist-info/METADATA | 616 - .../fastapi-0.138.0.dist-info/RECORD | 109 - .../fastapi-0.138.0.dist-info/REQUESTED | 0 .../fastapi-0.138.0.dist-info/WHEEL | 4 - .../entry_points.txt | 5 - .../licenses/LICENSE | 21 - .../Lib/site-packages/fastapi/__init__.py | 25 - .../Lib/site-packages/fastapi/__main__.py | 3 - .../site-packages/fastapi/_compat/__init__.py | 40 - .../site-packages/fastapi/_compat/shared.py | 214 - .../Lib/site-packages/fastapi/_compat/v2.py | 493 - .../Lib/site-packages/fastapi/applications.py | 4768 ----- .../Lib/site-packages/fastapi/background.py | 61 - server/venv/Lib/site-packages/fastapi/cli.py | 13 - .../Lib/site-packages/fastapi/concurrency.py | 41 - .../site-packages/fastapi/datastructures.py | 186 - .../fastapi/dependencies/__init__.py | 0 .../fastapi/dependencies/models.py | 193 - .../fastapi/dependencies/utils.py | 1061 - .../Lib/site-packages/fastapi/encoders.py | 364 - .../fastapi/exception_handlers.py | 34 - .../Lib/site-packages/fastapi/exceptions.py | 256 - .../venv/Lib/site-packages/fastapi/logger.py | 3 - .../fastapi/middleware/__init__.py | 1 - .../fastapi/middleware/asyncexitstack.py | 18 - .../site-packages/fastapi/middleware/cors.py | 1 - .../site-packages/fastapi/middleware/gzip.py | 1 - .../fastapi/middleware/httpsredirect.py | 3 - .../fastapi/middleware/trustedhost.py | 3 - .../site-packages/fastapi/middleware/wsgi.py | 3 - .../site-packages/fastapi/openapi/__init__.py | 0 .../fastapi/openapi/constants.py | 3 - .../Lib/site-packages/fastapi/openapi/docs.py | 389 - .../site-packages/fastapi/openapi/models.py | 435 - .../site-packages/fastapi/openapi/utils.py | 617 - .../site-packages/fastapi/param_functions.py | 2460 --- .../venv/Lib/site-packages/fastapi/params.py | 754 - .../venv/Lib/site-packages/fastapi/py.typed | 0 .../Lib/site-packages/fastapi/requests.py | 2 - .../Lib/site-packages/fastapi/responses.py | 98 - .../venv/Lib/site-packages/fastapi/routing.py | 6231 ------ .../fastapi/security/__init__.py | 15 - .../site-packages/fastapi/security/api_key.py | 320 - .../site-packages/fastapi/security/base.py | 6 - .../site-packages/fastapi/security/http.py | 417 - .../site-packages/fastapi/security/oauth2.py | 693 - .../fastapi/security/open_id_connect_url.py | 94 - .../site-packages/fastapi/security/utils.py | 7 - server/venv/Lib/site-packages/fastapi/sse.py | 235 - .../Lib/site-packages/fastapi/staticfiles.py | 1 - .../Lib/site-packages/fastapi/templating.py | 1 - .../Lib/site-packages/fastapi/testclient.py | 1 - .../venv/Lib/site-packages/fastapi/types.py | 12 - .../venv/Lib/site-packages/fastapi/utils.py | 136 - .../Lib/site-packages/fastapi/websockets.py | 3 - server/venv/Lib/site-packages/gssapi64.dll | Bin 412800 -> 0 bytes .../h11-0.16.0.dist-info/INSTALLER | 1 - .../h11-0.16.0.dist-info/METADATA | 202 - .../site-packages/h11-0.16.0.dist-info/RECORD | 29 - .../site-packages/h11-0.16.0.dist-info/WHEEL | 5 - .../h11-0.16.0.dist-info/licenses/LICENSE.txt | 22 - .../h11-0.16.0.dist-info/top_level.txt | 1 - server/venv/Lib/site-packages/h11/__init__.py | 62 - server/venv/Lib/site-packages/h11/_abnf.py | 132 - .../venv/Lib/site-packages/h11/_connection.py | 659 - server/venv/Lib/site-packages/h11/_events.py | 369 - server/venv/Lib/site-packages/h11/_headers.py | 282 - server/venv/Lib/site-packages/h11/_readers.py | 250 - .../Lib/site-packages/h11/_receivebuffer.py | 153 - server/venv/Lib/site-packages/h11/_state.py | 365 - server/venv/Lib/site-packages/h11/_util.py | 135 - server/venv/Lib/site-packages/h11/_version.py | 16 - server/venv/Lib/site-packages/h11/_writers.py | 145 - server/venv/Lib/site-packages/h11/py.typed | 1 - .../httptools-0.8.0.dist-info/INSTALLER | 1 - .../httptools-0.8.0.dist-info/METADATA | 131 - .../httptools-0.8.0.dist-info/RECORD | 28 - .../httptools-0.8.0.dist-info/WHEEL | 5 - .../licenses/LICENSE | 21 - .../licenses/vendor/http-parser/LICENSE-MIT | 19 - .../licenses/vendor/llhttp/LICENSE | 22 - .../httptools-0.8.0.dist-info/top_level.txt | 1 - .../Lib/site-packages/httptools/__init__.py | 35 - .../Lib/site-packages/httptools/_version.py | 13 - .../httptools/parser/__init__.py | 28 - .../httptools/parser/cparser.pxd | 167 - .../site-packages/httptools/parser/errors.py | 30 - .../parser/parser.cp313-win_amd64.pyd | Bin 123904 -> 0 bytes .../site-packages/httptools/parser/parser.pyi | 58 - .../site-packages/httptools/parser/parser.pyx | 436 - .../httptools/parser/protocol.py | 15 - .../site-packages/httptools/parser/python.pxd | 6 - .../httptools/parser/url_cparser.pxd | 31 - .../parser/url_parser.cp313-win_amd64.pyd | Bin 50688 -> 0 bytes .../httptools/parser/url_parser.pyi | 13 - .../httptools/parser/url_parser.pyx | 118 - .../venv/Lib/site-packages/httptools/py.typed | 0 .../idna-3.18.dist-info/INSTALLER | 1 - .../idna-3.18.dist-info/METADATA | 155 - .../site-packages/idna-3.18.dist-info/RECORD | 28 - .../site-packages/idna-3.18.dist-info/WHEEL | 4 - .../idna-3.18.dist-info/entry_points.txt | 3 - .../idna-3.18.dist-info/licenses/LICENSE.md | 31 - .../venv/Lib/site-packages/idna/__init__.py | 45 - .../venv/Lib/site-packages/idna/__main__.py | 6 - server/venv/Lib/site-packages/idna/cli.py | 128 - server/venv/Lib/site-packages/idna/codec.py | 159 - server/venv/Lib/site-packages/idna/compat.py | 41 - server/venv/Lib/site-packages/idna/core.py | 648 - .../venv/Lib/site-packages/idna/idnadata.py | 1897 -- .../venv/Lib/site-packages/idna/intranges.py | 55 - .../Lib/site-packages/idna/package_data.py | 1 - server/venv/Lib/site-packages/idna/py.typed | 0 .../venv/Lib/site-packages/idna/uts46data.py | 16896 ---------------- server/venv/Lib/site-packages/k5sprt64.dll | Bin 162432 -> 0 bytes server/venv/Lib/site-packages/krb5_64.dll | Bin 1237632 -> 0 bytes server/venv/Lib/site-packages/krbcc64.dll | Bin 122496 -> 0 bytes .../Lib/site-packages/libcrypto-3-x64.dll | Bin 7139984 -> 0 bytes server/venv/Lib/site-packages/libmysql.dll | Bin 7192704 -> 0 bytes server/venv/Lib/site-packages/libsasl.dll | Bin 120960 -> 0 bytes .../venv/Lib/site-packages/libssl-3-x64.dll | Bin 1314952 -> 0 bytes .../venv/Lib/site-packages/mysql/__init__.py | 27 - .../Lib/site-packages/mysql/ai/__init__.py | 27 - .../site-packages/mysql/ai/genai/__init__.py | 43 - .../site-packages/mysql/ai/genai/embedding.py | 197 - .../mysql/ai/genai/generation.py | 162 - .../mysql/ai/genai/vector_store.py | 520 - .../Lib/site-packages/mysql/ai/ml/__init__.py | 48 - .../Lib/site-packages/mysql/ai/ml/base.py | 142 - .../site-packages/mysql/ai/ml/classifier.py | 194 - .../Lib/site-packages/mysql/ai/ml/model.py | 780 - .../Lib/site-packages/mysql/ai/ml/outlier.py | 221 - .../site-packages/mysql/ai/ml/regressor.py | 154 - .../site-packages/mysql/ai/ml/transformer.py | 164 - .../site-packages/mysql/ai/utils/__init__.py | 44 - .../mysql/ai/utils/atomic_cursor.py | 94 - .../mysql/ai/utils/dependencies.py | 88 - .../Lib/site-packages/mysql/ai/utils/utils.py | 573 - .../site-packages/mysql/connector/__init__.py | 127 - .../mysql/connector/_decorating.py | 111 - .../mysql/connector/_scripting.py | 406 - .../mysql/connector/abstracts.py | 3185 --- .../mysql/connector/aio/__init__.py | 40 - .../mysql/connector/aio/_decorating.py | 112 - .../mysql/connector/aio/abstracts.py | 2703 --- .../mysql/connector/aio/authentication.py | 335 - .../mysql/connector/aio/charsets.py | 686 - .../mysql/connector/aio/connection.py | 1580 -- .../mysql/connector/aio/cursor.py | 1392 -- .../mysql/connector/aio/logger.py | 33 - .../mysql/connector/aio/network.py | 765 - .../mysql/connector/aio/plugins/__init__.py | 162 - .../plugins/authentication_kerberos_client.py | 577 - .../authentication_ldap_sasl_client.py | 595 - .../aio/plugins/authentication_oci_client.py | 234 - .../authentication_openid_connect_client.py | 172 - .../plugins/authentication_webauthn_client.py | 291 - .../aio/plugins/caching_sha2_password.py | 160 - .../aio/plugins/mysql_clear_password.py | 105 - .../aio/plugins/mysql_native_password.py | 121 - .../connector/aio/plugins/sha256_password.py | 109 - .../mysql/connector/aio/pooling.py | 688 - .../mysql/connector/aio/protocol.py | 325 - .../mysql/connector/aio/py.typed | 27 - .../mysql/connector/aio/utils.py | 155 - .../mysql/connector/authentication.py | 385 - .../site-packages/mysql/connector/charsets.py | 620 - .../mysql/connector/connection.py | 1784 -- .../mysql/connector/connection_cext.py | 1170 -- .../mysql/connector/constants.py | 1165 -- .../mysql/connector/conversion.py | 789 - .../site-packages/mysql/connector/cursor.py | 1489 -- .../mysql/connector/cursor_cext.py | 1275 -- .../mysql/connector/custom_types.py | 49 - .../site-packages/mysql/connector/dbapi.py | 92 - .../mysql/connector/django/__init__.py | 27 - .../mysql/connector/django/base.py | 654 - .../mysql/connector/django/client.py | 106 - .../mysql/connector/django/compiler.py | 45 - .../mysql/connector/django/creation.py | 33 - .../mysql/connector/django/features.py | 50 - .../mysql/connector/django/introspection.py | 461 - .../mysql/connector/django/operations.py | 104 - .../mysql/connector/django/schema.py | 59 - .../mysql/connector/django/validation.py | 33 - .../mysql/connector/errorcode.py | 1877 -- .../site-packages/mysql/connector/errors.py | 393 - .../mysql/connector/locales/__init__.py | 80 - .../mysql/connector/locales/eng/__init__.py | 30 - .../connector/locales/eng/client_error.py | 152 - .../site-packages/mysql/connector/logger.py | 33 - .../site-packages/mysql/connector/network.py | 811 - .../mysql/connector/opentelemetry/__init__.py | 27 - .../connector/opentelemetry/constants.py | 77 - .../opentelemetry/context_propagation.py | 112 - .../opentelemetry/instrumentation.py | 687 - .../mysql/connector/optionfiles.py | 367 - .../mysql/connector/plugins/__init__.py | 160 - .../plugins/authentication_kerberos_client.py | 576 - .../authentication_ldap_sasl_client.py | 595 - .../plugins/authentication_oci_client.py | 234 - .../authentication_openid_connect_client.py | 173 - .../plugins/authentication_webauthn_client.py | 290 - .../plugins/caching_sha2_password.py | 159 - .../connector/plugins/mysql_clear_password.py | 104 - .../plugins/mysql_native_password.py | 120 - .../connector/plugins/sha256_password.py | 108 - .../site-packages/mysql/connector/pooling.py | 699 - .../site-packages/mysql/connector/protocol.py | 1154 -- .../site-packages/mysql/connector/py.typed | 27 - .../mysql/connector/tls_ciphers.py | 168 - .../site-packages/mysql/connector/types.py | 214 - .../site-packages/mysql/connector/utils.py | 760 - .../site-packages/mysql/connector/version.py | 46 - .../mysql/vendor/libcrypto-3-x64.dll | Bin 7139984 -> 0 bytes .../site-packages/mysql/vendor/libsasl.dll | Bin 120960 -> 0 bytes .../mysql/vendor/libssl-3-x64.dll | Bin 1314952 -> 0 bytes .../plugin/authentication_kerberos_client.dll | Bin 6442160 -> 0 bytes .../authentication_ldap_sasl_client.dll | Bin 6434992 -> 0 bytes .../plugin/authentication_oci_client.dll | Bin 6494880 -> 0 bytes .../authentication_openid_connect_client.dll | Bin 6420152 -> 0 bytes .../plugin/authentication_webauthn_client.dll | Bin 6437040 -> 0 bytes .../vendor/plugin/mysql_native_password.dll | Bin 32408 -> 0 bytes .../INSTALLER | 1 - .../METADATA | 328 - .../RECORD | 213 - .../REQUESTED | 0 .../WHEEL | 5 - .../licenses/LICENSE.txt | 8125 -------- .../top_level.txt | 2 - .../venv/Lib/site-packages/paho/__init__.py | 0 .../Lib/site-packages/paho/mqtt/__init__.py | 5 - .../Lib/site-packages/paho/mqtt/client.py | 5004 ----- .../venv/Lib/site-packages/paho/mqtt/enums.py | 113 - .../Lib/site-packages/paho/mqtt/matcher.py | 78 - .../site-packages/paho/mqtt/packettypes.py | 43 - .../Lib/site-packages/paho/mqtt/properties.py | 421 - .../Lib/site-packages/paho/mqtt/publish.py | 306 - .../venv/Lib/site-packages/paho/mqtt/py.typed | 0 .../site-packages/paho/mqtt/reasoncodes.py | 223 - .../Lib/site-packages/paho/mqtt/subscribe.py | 281 - .../paho/mqtt/subscribeoptions.py | 113 - .../paho_mqtt-2.1.0.dist-info/INSTALLER | 1 - .../paho_mqtt-2.1.0.dist-info/METADATA | 635 - .../paho_mqtt-2.1.0.dist-info/RECORD | 29 - .../paho_mqtt-2.1.0.dist-info/REQUESTED | 0 .../paho_mqtt-2.1.0.dist-info/WHEEL | 4 - .../licenses/LICENSE.txt | 3 - .../pip-25.2.dist-info/INSTALLER | 1 - .../site-packages/pip-25.2.dist-info/METADATA | 112 - .../site-packages/pip-25.2.dist-info/RECORD | 860 - .../pip-25.2.dist-info/REQUESTED | 0 .../site-packages/pip-25.2.dist-info/WHEEL | 5 - .../pip-25.2.dist-info/entry_points.txt | 3 - .../pip-25.2.dist-info/licenses/AUTHORS.txt | 833 - .../pip-25.2.dist-info/licenses/LICENSE.txt | 20 - .../src/pip/_vendor/cachecontrol/LICENSE.txt | 13 - .../licenses/src/pip/_vendor/certifi/LICENSE | 20 - .../pip/_vendor/dependency_groups/LICENSE.txt | 9 - .../src/pip/_vendor/distlib/LICENSE.txt | 284 - .../licenses/src/pip/_vendor/distro/LICENSE | 202 - .../licenses/src/pip/_vendor/idna/LICENSE.md | 31 - .../licenses/src/pip/_vendor/msgpack/COPYING | 14 - .../src/pip/_vendor/packaging/LICENSE | 3 - .../src/pip/_vendor/packaging/LICENSE.APACHE | 177 - .../src/pip/_vendor/packaging/LICENSE.BSD | 23 - .../src/pip/_vendor/pkg_resources/LICENSE | 17 - .../src/pip/_vendor/platformdirs/LICENSE | 21 - .../licenses/src/pip/_vendor/pygments/LICENSE | 25 - .../src/pip/_vendor/pyproject_hooks/LICENSE | 21 - .../licenses/src/pip/_vendor/requests/LICENSE | 175 - .../src/pip/_vendor/resolvelib/LICENSE | 13 - .../licenses/src/pip/_vendor/rich/LICENSE | 19 - .../licenses/src/pip/_vendor/tomli/LICENSE | 21 - .../src/pip/_vendor/tomli/LICENSE-HEADER | 3 - .../licenses/src/pip/_vendor/tomli_w/LICENSE | 21 - .../src/pip/_vendor/truststore/LICENSE | 21 - .../src/pip/_vendor/urllib3/LICENSE.txt | 21 - .../pip-25.2.dist-info/top_level.txt | 1 - server/venv/Lib/site-packages/pip/__init__.py | 13 - server/venv/Lib/site-packages/pip/__main__.py | 24 - .../Lib/site-packages/pip/__pip-runner__.py | 50 - .../site-packages/pip/_internal/__init__.py | 18 - .../site-packages/pip/_internal/build_env.py | 349 - .../Lib/site-packages/pip/_internal/cache.py | 291 - .../pip/_internal/cli/__init__.py | 3 - .../pip/_internal/cli/autocompletion.py | 184 - .../pip/_internal/cli/base_command.py | 244 - .../pip/_internal/cli/cmdoptions.py | 1138 -- .../pip/_internal/cli/command_context.py | 28 - .../pip/_internal/cli/index_command.py | 175 - .../site-packages/pip/_internal/cli/main.py | 80 - .../pip/_internal/cli/main_parser.py | 134 - .../site-packages/pip/_internal/cli/parser.py | 298 - .../pip/_internal/cli/progress_bars.py | 151 - .../pip/_internal/cli/req_command.py | 351 - .../pip/_internal/cli/spinners.py | 235 - .../pip/_internal/cli/status_codes.py | 6 - .../pip/_internal/commands/__init__.py | 139 - .../pip/_internal/commands/cache.py | 231 - .../pip/_internal/commands/check.py | 66 - .../pip/_internal/commands/completion.py | 135 - .../pip/_internal/commands/configuration.py | 288 - .../pip/_internal/commands/debug.py | 203 - .../pip/_internal/commands/download.py | 145 - .../pip/_internal/commands/freeze.py | 107 - .../pip/_internal/commands/hash.py | 58 - .../pip/_internal/commands/help.py | 40 - .../pip/_internal/commands/index.py | 159 - .../pip/_internal/commands/inspect.py | 92 - .../pip/_internal/commands/install.py | 798 - .../pip/_internal/commands/list.py | 400 - .../pip/_internal/commands/lock.py | 170 - .../pip/_internal/commands/search.py | 178 - .../pip/_internal/commands/show.py | 231 - .../pip/_internal/commands/uninstall.py | 113 - .../pip/_internal/commands/wheel.py | 181 - .../pip/_internal/configuration.py | 397 - .../pip/_internal/distributions/__init__.py | 21 - .../pip/_internal/distributions/base.py | 55 - .../pip/_internal/distributions/installed.py | 33 - .../pip/_internal/distributions/sdist.py | 165 - .../pip/_internal/distributions/wheel.py | 44 - .../site-packages/pip/_internal/exceptions.py | 881 - .../pip/_internal/index/__init__.py | 1 - .../pip/_internal/index/collector.py | 489 - .../pip/_internal/index/package_finder.py | 1059 - .../pip/_internal/index/sources.py | 287 - .../pip/_internal/locations/__init__.py | 441 - .../pip/_internal/locations/_distutils.py | 173 - .../pip/_internal/locations/_sysconfig.py | 215 - .../pip/_internal/locations/base.py | 82 - .../Lib/site-packages/pip/_internal/main.py | 12 - .../pip/_internal/metadata/__init__.py | 164 - .../pip/_internal/metadata/_json.py | 87 - .../pip/_internal/metadata/base.py | 685 - .../_internal/metadata/importlib/__init__.py | 6 - .../_internal/metadata/importlib/_compat.py | 87 - .../_internal/metadata/importlib/_dists.py | 223 - .../pip/_internal/metadata/importlib/_envs.py | 143 - .../pip/_internal/metadata/pkg_resources.py | 298 - .../pip/_internal/models/__init__.py | 1 - .../pip/_internal/models/candidate.py | 25 - .../pip/_internal/models/direct_url.py | 227 - .../pip/_internal/models/format_control.py | 78 - .../pip/_internal/models/index.py | 28 - .../_internal/models/installation_report.py | 57 - .../pip/_internal/models/link.py | 613 - .../pip/_internal/models/pylock.py | 188 - .../pip/_internal/models/scheme.py | 25 - .../pip/_internal/models/search_scope.py | 126 - .../pip/_internal/models/selection_prefs.py | 53 - .../pip/_internal/models/target_python.py | 122 - .../pip/_internal/models/wheel.py | 141 - .../pip/_internal/network/__init__.py | 1 - .../pip/_internal/network/auth.py | 564 - .../pip/_internal/network/cache.py | 133 - .../pip/_internal/network/download.py | 342 - .../pip/_internal/network/lazy_wheel.py | 213 - .../pip/_internal/network/session.py | 528 - .../pip/_internal/network/utils.py | 98 - .../pip/_internal/network/xmlrpc.py | 61 - .../pip/_internal/operations/__init__.py | 0 .../_internal/operations/build/__init__.py | 0 .../operations/build/build_tracker.py | 140 - .../_internal/operations/build/metadata.py | 38 - .../operations/build/metadata_editable.py | 41 - .../operations/build/metadata_legacy.py | 73 - .../pip/_internal/operations/build/wheel.py | 38 - .../operations/build/wheel_editable.py | 47 - .../operations/build/wheel_legacy.py | 119 - .../pip/_internal/operations/check.py | 175 - .../pip/_internal/operations/freeze.py | 259 - .../_internal/operations/install/__init__.py | 1 - .../operations/install/editable_legacy.py | 48 - .../pip/_internal/operations/install/wheel.py | 746 - .../pip/_internal/operations/prepare.py | 742 - .../site-packages/pip/_internal/pyproject.py | 182 - .../pip/_internal/req/__init__.py | 105 - .../pip/_internal/req/constructors.py | 562 - .../pip/_internal/req/req_dependency_group.py | 75 - .../pip/_internal/req/req_file.py | 620 - .../pip/_internal/req/req_install.py | 937 - .../pip/_internal/req/req_set.py | 81 - .../pip/_internal/req/req_uninstall.py | 639 - .../pip/_internal/resolution/__init__.py | 0 .../pip/_internal/resolution/base.py | 20 - .../_internal/resolution/legacy/__init__.py | 0 .../_internal/resolution/legacy/resolver.py | 598 - .../resolution/resolvelib/__init__.py | 0 .../_internal/resolution/resolvelib/base.py | 142 - .../resolution/resolvelib/candidates.py | 582 - .../resolution/resolvelib/factory.py | 814 - .../resolution/resolvelib/found_candidates.py | 166 - .../resolution/resolvelib/provider.py | 276 - .../resolution/resolvelib/reporter.py | 85 - .../resolution/resolvelib/requirements.py | 247 - .../resolution/resolvelib/resolver.py | 336 - .../pip/_internal/self_outdated_check.py | 254 - .../pip/_internal/utils/__init__.py | 0 .../pip/_internal/utils/_jaraco_text.py | 109 - .../site-packages/pip/_internal/utils/_log.py | 38 - .../pip/_internal/utils/appdirs.py | 52 - .../pip/_internal/utils/compat.py | 85 - .../pip/_internal/utils/compatibility_tags.py | 201 - .../pip/_internal/utils/datetime.py | 10 - .../pip/_internal/utils/deprecation.py | 126 - .../pip/_internal/utils/direct_url_helpers.py | 87 - .../pip/_internal/utils/egg_link.py | 81 - .../pip/_internal/utils/entrypoints.py | 88 - .../pip/_internal/utils/filesystem.py | 152 - .../pip/_internal/utils/filetypes.py | 24 - .../pip/_internal/utils/glibc.py | 102 - .../pip/_internal/utils/hashes.py | 150 - .../pip/_internal/utils/logging.py | 364 - .../site-packages/pip/_internal/utils/misc.py | 765 - .../pip/_internal/utils/packaging.py | 44 - .../pip/_internal/utils/retry.py | 45 - .../pip/_internal/utils/setuptools_build.py | 149 - .../pip/_internal/utils/subprocess.py | 248 - .../pip/_internal/utils/temp_dir.py | 294 - .../pip/_internal/utils/unpacking.py | 337 - .../site-packages/pip/_internal/utils/urls.py | 55 - .../pip/_internal/utils/virtualenv.py | 105 - .../pip/_internal/utils/wheel.py | 132 - .../pip/_internal/vcs/__init__.py | 15 - .../site-packages/pip/_internal/vcs/bazaar.py | 130 - .../site-packages/pip/_internal/vcs/git.py | 571 - .../pip/_internal/vcs/mercurial.py | 186 - .../pip/_internal/vcs/subversion.py | 335 - .../pip/_internal/vcs/versioncontrol.py | 693 - .../pip/_internal/wheel_builder.py | 334 - .../Lib/site-packages/pip/_vendor/__init__.py | 117 - .../pip/_vendor/cachecontrol/__init__.py | 29 - .../pip/_vendor/cachecontrol/_cmd.py | 70 - .../pip/_vendor/cachecontrol/adapter.py | 168 - .../pip/_vendor/cachecontrol/cache.py | 75 - .../_vendor/cachecontrol/caches/__init__.py | 8 - .../_vendor/cachecontrol/caches/file_cache.py | 145 - .../cachecontrol/caches/redis_cache.py | 48 - .../pip/_vendor/cachecontrol/controller.py | 511 - .../pip/_vendor/cachecontrol/filewrapper.py | 119 - .../pip/_vendor/cachecontrol/heuristics.py | 157 - .../pip/_vendor/cachecontrol/py.typed | 0 .../pip/_vendor/cachecontrol/serialize.py | 146 - .../pip/_vendor/cachecontrol/wrapper.py | 43 - .../pip/_vendor/certifi/__init__.py | 4 - .../pip/_vendor/certifi/__main__.py | 12 - .../pip/_vendor/certifi/cacert.pem | 4778 ----- .../site-packages/pip/_vendor/certifi/core.py | 83 - .../pip/_vendor/certifi/py.typed | 0 .../pip/_vendor/dependency_groups/__init__.py | 13 - .../pip/_vendor/dependency_groups/__main__.py | 65 - .../dependency_groups/_implementation.py | 209 - .../_lint_dependency_groups.py | 59 - .../_vendor/dependency_groups/_pip_wrapper.py | 62 - .../_vendor/dependency_groups/_toml_compat.py | 9 - .../pip/_vendor/dependency_groups/py.typed | 0 .../pip/_vendor/distlib/__init__.py | 33 - .../pip/_vendor/distlib/compat.py | 1137 -- .../pip/_vendor/distlib/resources.py | 358 - .../pip/_vendor/distlib/scripts.py | 447 - .../site-packages/pip/_vendor/distlib/t32.exe | Bin 97792 -> 0 bytes .../pip/_vendor/distlib/t64-arm.exe | Bin 182784 -> 0 bytes .../site-packages/pip/_vendor/distlib/t64.exe | Bin 108032 -> 0 bytes .../site-packages/pip/_vendor/distlib/util.py | 1984 -- .../site-packages/pip/_vendor/distlib/w32.exe | Bin 91648 -> 0 bytes .../pip/_vendor/distlib/w64-arm.exe | Bin 168448 -> 0 bytes .../site-packages/pip/_vendor/distlib/w64.exe | Bin 101888 -> 0 bytes .../pip/_vendor/distro/__init__.py | 54 - .../pip/_vendor/distro/__main__.py | 4 - .../pip/_vendor/distro/distro.py | 1403 -- .../site-packages/pip/_vendor/distro/py.typed | 0 .../pip/_vendor/idna/__init__.py | 45 - .../site-packages/pip/_vendor/idna/codec.py | 122 - .../site-packages/pip/_vendor/idna/compat.py | 15 - .../site-packages/pip/_vendor/idna/core.py | 437 - .../pip/_vendor/idna/idnadata.py | 4243 ---- .../pip/_vendor/idna/intranges.py | 57 - .../pip/_vendor/idna/package_data.py | 1 - .../site-packages/pip/_vendor/idna/py.typed | 0 .../pip/_vendor/idna/uts46data.py | 8681 -------- .../pip/_vendor/msgpack/__init__.py | 55 - .../pip/_vendor/msgpack/exceptions.py | 48 - .../site-packages/pip/_vendor/msgpack/ext.py | 170 - .../pip/_vendor/msgpack/fallback.py | 929 - .../pip/_vendor/packaging/__init__.py | 15 - .../pip/_vendor/packaging/_elffile.py | 109 - .../pip/_vendor/packaging/_manylinux.py | 262 - .../pip/_vendor/packaging/_musllinux.py | 85 - .../pip/_vendor/packaging/_parser.py | 353 - .../pip/_vendor/packaging/_structures.py | 61 - .../pip/_vendor/packaging/_tokenizer.py | 195 - .../_vendor/packaging/licenses/__init__.py | 145 - .../pip/_vendor/packaging/licenses/_spdx.py | 759 - .../pip/_vendor/packaging/markers.py | 362 - .../pip/_vendor/packaging/metadata.py | 862 - .../pip/_vendor/packaging/py.typed | 0 .../pip/_vendor/packaging/requirements.py | 91 - .../pip/_vendor/packaging/specifiers.py | 1019 - .../pip/_vendor/packaging/tags.py | 656 - .../pip/_vendor/packaging/utils.py | 163 - .../pip/_vendor/packaging/version.py | 582 - .../pip/_vendor/pkg_resources/__init__.py | 3676 ---- .../pip/_vendor/platformdirs/__init__.py | 631 - .../pip/_vendor/platformdirs/__main__.py | 55 - .../pip/_vendor/platformdirs/android.py | 249 - .../pip/_vendor/platformdirs/api.py | 299 - .../pip/_vendor/platformdirs/macos.py | 144 - .../pip/_vendor/platformdirs/py.typed | 0 .../pip/_vendor/platformdirs/unix.py | 272 - .../pip/_vendor/platformdirs/version.py | 21 - .../pip/_vendor/platformdirs/windows.py | 272 - .../pip/_vendor/pygments/__init__.py | 82 - .../pip/_vendor/pygments/__main__.py | 17 - .../pip/_vendor/pygments/console.py | 70 - .../pip/_vendor/pygments/filter.py | 70 - .../pip/_vendor/pygments/filters/__init__.py | 940 - .../pip/_vendor/pygments/formatter.py | 129 - .../_vendor/pygments/formatters/__init__.py | 157 - .../_vendor/pygments/formatters/_mapping.py | 23 - .../pip/_vendor/pygments/lexer.py | 963 - .../pip/_vendor/pygments/lexers/__init__.py | 362 - .../pip/_vendor/pygments/lexers/_mapping.py | 602 - .../pip/_vendor/pygments/lexers/python.py | 1201 -- .../pip/_vendor/pygments/modeline.py | 43 - .../pip/_vendor/pygments/plugin.py | 72 - .../pip/_vendor/pygments/regexopt.py | 91 - .../pip/_vendor/pygments/scanner.py | 104 - .../pip/_vendor/pygments/sphinxext.py | 247 - .../pip/_vendor/pygments/style.py | 203 - .../pip/_vendor/pygments/styles/__init__.py | 61 - .../pip/_vendor/pygments/styles/_mapping.py | 54 - .../pip/_vendor/pygments/token.py | 214 - .../pip/_vendor/pygments/unistring.py | 153 - .../pip/_vendor/pygments/util.py | 324 - .../pip/_vendor/pyproject_hooks/__init__.py | 31 - .../pip/_vendor/pyproject_hooks/_impl.py | 410 - .../pyproject_hooks/_in_process/__init__.py | 21 - .../_in_process/_in_process.py | 389 - .../pip/_vendor/pyproject_hooks/py.typed | 0 .../pip/_vendor/requests/__init__.py | 179 - .../pip/_vendor/requests/__version__.py | 14 - .../pip/_vendor/requests/_internal_utils.py | 50 - .../pip/_vendor/requests/adapters.py | 719 - .../site-packages/pip/_vendor/requests/api.py | 157 - .../pip/_vendor/requests/auth.py | 314 - .../pip/_vendor/requests/certs.py | 17 - .../pip/_vendor/requests/compat.py | 90 - .../pip/_vendor/requests/cookies.py | 561 - .../pip/_vendor/requests/exceptions.py | 151 - .../pip/_vendor/requests/help.py | 127 - .../pip/_vendor/requests/hooks.py | 33 - .../pip/_vendor/requests/models.py | 1039 - .../pip/_vendor/requests/packages.py | 25 - .../pip/_vendor/requests/sessions.py | 831 - .../pip/_vendor/requests/status_codes.py | 128 - .../pip/_vendor/requests/structures.py | 99 - .../pip/_vendor/requests/utils.py | 1086 - .../pip/_vendor/resolvelib/__init__.py | 27 - .../pip/_vendor/resolvelib/providers.py | 196 - .../pip/_vendor/resolvelib/py.typed | 0 .../pip/_vendor/resolvelib/reporters.py | 55 - .../_vendor/resolvelib/resolvers/__init__.py | 27 - .../_vendor/resolvelib/resolvers/abstract.py | 47 - .../_vendor/resolvelib/resolvers/criterion.py | 48 - .../resolvelib/resolvers/exceptions.py | 57 - .../resolvelib/resolvers/resolution.py | 622 - .../pip/_vendor/resolvelib/structs.py | 209 - .../pip/_vendor/rich/__init__.py | 177 - .../pip/_vendor/rich/__main__.py | 245 - .../pip/_vendor/rich/_cell_widths.py | 454 - .../pip/_vendor/rich/_emoji_codes.py | 3610 ---- .../pip/_vendor/rich/_emoji_replace.py | 32 - .../pip/_vendor/rich/_export_format.py | 76 - .../pip/_vendor/rich/_extension.py | 10 - .../site-packages/pip/_vendor/rich/_fileno.py | 24 - .../pip/_vendor/rich/_inspect.py | 268 - .../pip/_vendor/rich/_log_render.py | 94 - .../site-packages/pip/_vendor/rich/_loop.py | 43 - .../pip/_vendor/rich/_null_file.py | 69 - .../pip/_vendor/rich/_palettes.py | 309 - .../site-packages/pip/_vendor/rich/_pick.py | 17 - .../site-packages/pip/_vendor/rich/_ratio.py | 153 - .../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 | 661 - .../pip/_vendor/rich/_windows.py | 71 - .../pip/_vendor/rich/_windows_renderer.py | 56 - .../site-packages/pip/_vendor/rich/_wrap.py | 93 - .../Lib/site-packages/pip/_vendor/rich/abc.py | 33 - .../site-packages/pip/_vendor/rich/align.py | 306 - .../site-packages/pip/_vendor/rich/ansi.py | 241 - .../Lib/site-packages/pip/_vendor/rich/bar.py | 93 - .../Lib/site-packages/pip/_vendor/rich/box.py | 474 - .../site-packages/pip/_vendor/rich/cells.py | 174 - .../site-packages/pip/_vendor/rich/color.py | 621 - .../pip/_vendor/rich/color_triplet.py | 38 - .../site-packages/pip/_vendor/rich/columns.py | 187 - .../site-packages/pip/_vendor/rich/console.py | 2680 --- .../pip/_vendor/rich/constrain.py | 37 - .../pip/_vendor/rich/containers.py | 167 - .../site-packages/pip/_vendor/rich/control.py | 219 - .../pip/_vendor/rich/default_styles.py | 193 - .../pip/_vendor/rich/diagnose.py | 39 - .../site-packages/pip/_vendor/rich/emoji.py | 91 - .../site-packages/pip/_vendor/rich/errors.py | 34 - .../pip/_vendor/rich/file_proxy.py | 57 - .../pip/_vendor/rich/filesize.py | 88 - .../pip/_vendor/rich/highlighter.py | 232 - .../site-packages/pip/_vendor/rich/json.py | 139 - .../site-packages/pip/_vendor/rich/jupyter.py | 101 - .../site-packages/pip/_vendor/rich/layout.py | 442 - .../site-packages/pip/_vendor/rich/live.py | 400 - .../pip/_vendor/rich/live_render.py | 106 - .../site-packages/pip/_vendor/rich/logging.py | 297 - .../site-packages/pip/_vendor/rich/markup.py | 251 - .../site-packages/pip/_vendor/rich/measure.py | 151 - .../site-packages/pip/_vendor/rich/padding.py | 141 - .../site-packages/pip/_vendor/rich/pager.py | 34 - .../site-packages/pip/_vendor/rich/palette.py | 100 - .../site-packages/pip/_vendor/rich/panel.py | 317 - .../site-packages/pip/_vendor/rich/pretty.py | 1016 - .../pip/_vendor/rich/progress.py | 1715 -- .../pip/_vendor/rich/progress_bar.py | 223 - .../site-packages/pip/_vendor/rich/prompt.py | 400 - .../pip/_vendor/rich/protocol.py | 42 - .../site-packages/pip/_vendor/rich/py.typed | 0 .../site-packages/pip/_vendor/rich/region.py | 10 - .../site-packages/pip/_vendor/rich/repr.py | 149 - .../site-packages/pip/_vendor/rich/rule.py | 130 - .../site-packages/pip/_vendor/rich/scope.py | 86 - .../site-packages/pip/_vendor/rich/screen.py | 54 - .../site-packages/pip/_vendor/rich/segment.py | 752 - .../site-packages/pip/_vendor/rich/spinner.py | 132 - .../site-packages/pip/_vendor/rich/status.py | 131 - .../site-packages/pip/_vendor/rich/style.py | 796 - .../site-packages/pip/_vendor/rich/styled.py | 42 - .../site-packages/pip/_vendor/rich/syntax.py | 985 - .../site-packages/pip/_vendor/rich/table.py | 1006 - .../pip/_vendor/rich/terminal_theme.py | 153 - .../site-packages/pip/_vendor/rich/text.py | 1361 -- .../site-packages/pip/_vendor/rich/theme.py | 115 - .../site-packages/pip/_vendor/rich/themes.py | 5 - .../pip/_vendor/rich/traceback.py | 899 - .../site-packages/pip/_vendor/rich/tree.py | 257 - .../pip/_vendor/tomli/__init__.py | 8 - .../pip/_vendor/tomli/_parser.py | 770 - .../site-packages/pip/_vendor/tomli/_re.py | 112 - .../site-packages/pip/_vendor/tomli/_types.py | 10 - .../site-packages/pip/_vendor/tomli/py.typed | 1 - .../pip/_vendor/tomli_w/__init__.py | 4 - .../pip/_vendor/tomli_w/_writer.py | 229 - .../pip/_vendor/tomli_w/py.typed | 1 - .../pip/_vendor/truststore/__init__.py | 36 - .../pip/_vendor/truststore/_api.py | 333 - .../pip/_vendor/truststore/_macos.py | 571 - .../pip/_vendor/truststore/_openssl.py | 66 - .../pip/_vendor/truststore/_ssl_constants.py | 31 - .../pip/_vendor/truststore/_windows.py | 567 - .../pip/_vendor/truststore/py.typed | 0 .../pip/_vendor/urllib3/__init__.py | 102 - .../pip/_vendor/urllib3/_collections.py | 355 - .../pip/_vendor/urllib3/_version.py | 2 - .../pip/_vendor/urllib3/connection.py | 572 - .../pip/_vendor/urllib3/connectionpool.py | 1140 -- .../pip/_vendor/urllib3/contrib/__init__.py | 0 .../urllib3/contrib/_appengine_environ.py | 36 - .../contrib/_securetransport/__init__.py | 0 .../contrib/_securetransport/bindings.py | 519 - .../contrib/_securetransport/low_level.py | 397 - .../pip/_vendor/urllib3/contrib/appengine.py | 314 - .../pip/_vendor/urllib3/contrib/ntlmpool.py | 130 - .../pip/_vendor/urllib3/contrib/pyopenssl.py | 518 - .../urllib3/contrib/securetransport.py | 920 - .../pip/_vendor/urllib3/contrib/socks.py | 216 - .../pip/_vendor/urllib3/exceptions.py | 323 - .../pip/_vendor/urllib3/fields.py | 274 - .../pip/_vendor/urllib3/filepost.py | 98 - .../pip/_vendor/urllib3/packages/__init__.py | 0 .../urllib3/packages/backports/__init__.py | 0 .../urllib3/packages/backports/makefile.py | 51 - .../packages/backports/weakref_finalize.py | 155 - .../pip/_vendor/urllib3/packages/six.py | 1076 - .../pip/_vendor/urllib3/poolmanager.py | 540 - .../pip/_vendor/urllib3/request.py | 191 - .../pip/_vendor/urllib3/response.py | 879 - .../pip/_vendor/urllib3/util/__init__.py | 49 - .../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 | 622 - .../pip/_vendor/urllib3/util/ssl_.py | 504 - .../urllib3/util/ssl_match_hostname.py | 159 - .../pip/_vendor/urllib3/util/ssltransport.py | 221 - .../pip/_vendor/urllib3/util/timeout.py | 271 - .../pip/_vendor/urllib3/util/url.py | 435 - .../pip/_vendor/urllib3/util/wait.py | 152 - .../Lib/site-packages/pip/_vendor/vendor.txt | 19 - server/venv/Lib/site-packages/pip/py.typed | 4 - .../pydantic-2.13.4.dist-info/INSTALLER | 1 - .../pydantic-2.13.4.dist-info/METADATA | 1294 -- .../pydantic-2.13.4.dist-info/RECORD | 217 - .../pydantic-2.13.4.dist-info/WHEEL | 4 - .../licenses/LICENSE | 21 - .../Lib/site-packages/pydantic/__init__.py | 456 - .../pydantic/_internal/__init__.py | 0 .../pydantic/_internal/_config.py | 386 - .../pydantic/_internal/_core_metadata.py | 97 - .../pydantic/_internal/_core_utils.py | 174 - .../pydantic/_internal/_dataclasses.py | 315 - .../pydantic/_internal/_decorators.py | 873 - .../pydantic/_internal/_decorators_v1.py | 174 - .../_internal/_discriminated_union.py | 494 - .../pydantic/_internal/_docs_extraction.py | 113 - .../pydantic/_internal/_fields.py | 729 - .../pydantic/_internal/_forward_ref.py | 23 - .../pydantic/_internal/_generate_schema.py | 2934 --- .../pydantic/_internal/_generics.py | 530 - .../site-packages/pydantic/_internal/_git.py | 27 - .../pydantic/_internal/_import_utils.py | 20 - .../pydantic/_internal/_internal_dataclass.py | 7 - .../_internal/_known_annotated_metadata.py | 403 - .../pydantic/_internal/_mock_val_ser.py | 228 - .../pydantic/_internal/_model_construction.py | 868 - .../pydantic/_internal/_namespace_utils.py | 293 - .../site-packages/pydantic/_internal/_repr.py | 124 - .../pydantic/_internal/_schema_gather.py | 212 - .../_internal/_schema_generation_shared.py | 125 - .../pydantic/_internal/_serializers.py | 53 - .../pydantic/_internal/_signature.py | 189 - .../pydantic/_internal/_typing_extra.py | 785 - .../pydantic/_internal/_utils.py | 446 - .../pydantic/_internal/_validate_call.py | 141 - .../pydantic/_internal/_validators.py | 534 - .../Lib/site-packages/pydantic/_migration.py | 316 - .../pydantic/alias_generators.py | 62 - .../Lib/site-packages/pydantic/aliases.py | 135 - .../pydantic/annotated_handlers.py | 122 - .../pydantic/class_validators.py | 5 - .../venv/Lib/site-packages/pydantic/color.py | 604 - .../venv/Lib/site-packages/pydantic/config.py | 1296 -- .../Lib/site-packages/pydantic/dataclasses.py | 413 - .../site-packages/pydantic/datetime_parse.py | 5 - .../Lib/site-packages/pydantic/decorator.py | 5 - .../pydantic/deprecated/__init__.py | 0 .../pydantic/deprecated/class_validators.py | 256 - .../pydantic/deprecated/config.py | 72 - .../pydantic/deprecated/copy_internals.py | 224 - .../pydantic/deprecated/decorator.py | 284 - .../site-packages/pydantic/deprecated/json.py | 141 - .../pydantic/deprecated/parse.py | 80 - .../pydantic/deprecated/tools.py | 103 - .../site-packages/pydantic/env_settings.py | 5 - .../site-packages/pydantic/error_wrappers.py | 5 - .../venv/Lib/site-packages/pydantic/errors.py | 189 - .../pydantic/experimental/__init__.py | 1 - .../pydantic/experimental/arguments_schema.py | 44 - .../pydantic/experimental/missing_sentinel.py | 5 - .../pydantic/experimental/pipeline.py | 663 - .../venv/Lib/site-packages/pydantic/fields.py | 1892 -- .../pydantic/functional_serializers.py | 470 - .../pydantic/functional_validators.py | 889 - .../Lib/site-packages/pydantic/generics.py | 5 - .../venv/Lib/site-packages/pydantic/json.py | 5 - .../Lib/site-packages/pydantic/json_schema.py | 2911 --- .../venv/Lib/site-packages/pydantic/main.py | 1838 -- .../venv/Lib/site-packages/pydantic/mypy.py | 1412 -- .../Lib/site-packages/pydantic/networks.py | 1332 -- .../venv/Lib/site-packages/pydantic/parse.py | 5 - .../site-packages/pydantic/plugin/__init__.py | 193 - .../site-packages/pydantic/plugin/_loader.py | 58 - .../pydantic/plugin/_schema_validator.py | 143 - .../venv/Lib/site-packages/pydantic/py.typed | 0 .../Lib/site-packages/pydantic/root_model.py | 157 - .../venv/Lib/site-packages/pydantic/schema.py | 5 - .../venv/Lib/site-packages/pydantic/tools.py | 5 - .../site-packages/pydantic/type_adapter.py | 801 - .../venv/Lib/site-packages/pydantic/types.py | 3310 --- .../venv/Lib/site-packages/pydantic/typing.py | 5 - .../venv/Lib/site-packages/pydantic/utils.py | 5 - .../Lib/site-packages/pydantic/v1/__init__.py | 131 - .../pydantic/v1/_hypothesis_plugin.py | 391 - .../pydantic/v1/annotated_types.py | 72 - .../pydantic/v1/class_validators.py | 361 - .../Lib/site-packages/pydantic/v1/color.py | 494 - .../Lib/site-packages/pydantic/v1/config.py | 191 - .../site-packages/pydantic/v1/dataclasses.py | 500 - .../pydantic/v1/datetime_parse.py | 248 - .../site-packages/pydantic/v1/decorator.py | 264 - .../site-packages/pydantic/v1/env_settings.py | 350 - .../pydantic/v1/error_wrappers.py | 161 - .../Lib/site-packages/pydantic/v1/errors.py | 646 - .../Lib/site-packages/pydantic/v1/fields.py | 1253 -- .../Lib/site-packages/pydantic/v1/generics.py | 400 - .../Lib/site-packages/pydantic/v1/json.py | 112 - .../Lib/site-packages/pydantic/v1/main.py | 1130 -- .../Lib/site-packages/pydantic/v1/mypy.py | 949 - .../Lib/site-packages/pydantic/v1/networks.py | 747 - .../Lib/site-packages/pydantic/v1/parse.py | 66 - .../Lib/site-packages/pydantic/v1/py.typed | 0 .../Lib/site-packages/pydantic/v1/schema.py | 1163 -- .../Lib/site-packages/pydantic/v1/tools.py | 92 - .../Lib/site-packages/pydantic/v1/types.py | 1205 -- .../Lib/site-packages/pydantic/v1/typing.py | 627 - .../Lib/site-packages/pydantic/v1/utils.py | 807 - .../site-packages/pydantic/v1/validators.py | 768 - .../Lib/site-packages/pydantic/v1/version.py | 38 - .../pydantic/validate_call_decorator.py | 116 - .../Lib/site-packages/pydantic/validators.py | 5 - .../Lib/site-packages/pydantic/version.py | 113 - .../Lib/site-packages/pydantic/warnings.py | 122 - .../pydantic_core-2.46.4.dist-info/INSTALLER | 1 - .../pydantic_core-2.46.4.dist-info/METADATA | 173 - .../pydantic_core-2.46.4.dist-info/RECORD | 13 - .../pydantic_core-2.46.4.dist-info/WHEEL | 4 - .../licenses/LICENSE | 21 - .../sboms/pydantic-core.cyclonedx.json | 3961 ---- .../site-packages/pydantic_core/__init__.py | 171 - .../_pydantic_core.cp313-win_amd64.pyd | Bin 5256192 -> 0 bytes .../pydantic_core/_pydantic_core.pyi | 1056 - .../pydantic_core/core_schema.py | 4461 ---- .../Lib/site-packages/pydantic_core/py.typed | 0 .../python_dotenv-1.2.2.dist-info/INSTALLER | 1 - .../python_dotenv-1.2.2.dist-info/METADATA | 794 - .../python_dotenv-1.2.2.dist-info/RECORD | 25 - .../python_dotenv-1.2.2.dist-info/WHEEL | 5 - .../entry_points.txt | 2 - .../licenses/LICENSE | 27 - .../top_level.txt | 1 - .../pyyaml-6.0.3.dist-info/INSTALLER | 1 - .../pyyaml-6.0.3.dist-info/METADATA | 59 - .../pyyaml-6.0.3.dist-info/RECORD | 43 - .../pyyaml-6.0.3.dist-info/WHEEL | 5 - .../pyyaml-6.0.3.dist-info/licenses/LICENSE | 20 - .../pyyaml-6.0.3.dist-info/top_level.txt | 2 - .../Lib/site-packages/sasl2/saslGSSAPI.dll | Bin 46728 -> 0 bytes .../Lib/site-packages/sasl2/saslSCRAM.dll | Bin 57472 -> 0 bytes .../starlette-1.3.1.dist-info/INSTALLER | 1 - .../starlette-1.3.1.dist-info/METADATA | 178 - .../starlette-1.3.1.dist-info/RECORD | 74 - .../starlette-1.3.1.dist-info/WHEEL | 4 - .../licenses/LICENSE.md | 27 - .../Lib/site-packages/starlette/__init__.py | 1 - .../starlette/_exception_handler.py | 65 - .../Lib/site-packages/starlette/_utils.py | 111 - .../site-packages/starlette/applications.py | 118 - .../site-packages/starlette/authentication.py | 149 - .../Lib/site-packages/starlette/background.py | 36 - .../site-packages/starlette/concurrency.py | 59 - .../Lib/site-packages/starlette/config.py | 140 - .../Lib/site-packages/starlette/convertors.py | 89 - .../site-packages/starlette/datastructures.py | 704 - .../Lib/site-packages/starlette/endpoints.py | 127 - .../Lib/site-packages/starlette/exceptions.py | 43 - .../site-packages/starlette/formparsers.py | 297 - .../starlette/middleware/__init__.py | 37 - .../starlette/middleware/authentication.py | 52 - .../starlette/middleware/base.py | 244 - .../starlette/middleware/cors.py | 179 - .../starlette/middleware/errors.py | 259 - .../starlette/middleware/exceptions.py | 73 - .../starlette/middleware/gzip.py | 145 - .../starlette/middleware/httpsredirect.py | 19 - .../starlette/middleware/sessions.py | 125 - .../starlette/middleware/trustedhost.py | 60 - .../starlette/middleware/wsgi.py | 156 - .../venv/Lib/site-packages/starlette/py.typed | 0 .../Lib/site-packages/starlette/requests.py | 348 - .../Lib/site-packages/starlette/responses.py | 567 - .../Lib/site-packages/starlette/routing.py | 747 - .../Lib/site-packages/starlette/schemas.py | 148 - .../site-packages/starlette/staticfiles.py | 223 - .../Lib/site-packages/starlette/status.py | 211 - .../Lib/site-packages/starlette/templating.py | 156 - .../Lib/site-packages/starlette/testclient.py | 748 - .../venv/Lib/site-packages/starlette/types.py | 26 - .../Lib/site-packages/starlette/websockets.py | 196 - .../INSTALLER | 1 - .../METADATA | 72 - .../typing_extensions-4.15.0.dist-info/RECORD | 7 - .../typing_extensions-4.15.0.dist-info/WHEEL | 4 - .../licenses/LICENSE | 279 - .../Lib/site-packages/typing_extensions.py | 4317 ---- .../INSTALLER | 1 - .../METADATA | 49 - .../typing_inspection-0.4.2.dist-info/RECORD | 13 - .../typing_inspection-0.4.2.dist-info/WHEEL | 4 - .../licenses/LICENSE | 21 - .../typing_inspection/__init__.py | 0 .../typing_inspection/introspection.py | 587 - .../site-packages/typing_inspection/py.typed | 0 .../typing_inspection/typing_objects.py | 607 - .../typing_inspection/typing_objects.pyi | 417 - .../uvicorn-0.49.0.dist-info/INSTALLER | 1 - .../uvicorn-0.49.0.dist-info/METADATA | 191 - .../uvicorn-0.49.0.dist-info/RECORD | 89 - .../uvicorn-0.49.0.dist-info/REQUESTED | 0 .../uvicorn-0.49.0.dist-info/WHEEL | 4 - .../uvicorn-0.49.0.dist-info/entry_points.txt | 2 - .../licenses/LICENSE.md | 27 - .../Lib/site-packages/uvicorn/__init__.py | 5 - .../Lib/site-packages/uvicorn/__main__.py | 4 - .../venv/Lib/site-packages/uvicorn/_compat.py | 91 - .../Lib/site-packages/uvicorn/_subprocess.py | 84 - .../venv/Lib/site-packages/uvicorn/_types.py | 274 - .../venv/Lib/site-packages/uvicorn/config.py | 588 - .../Lib/site-packages/uvicorn/importer.py | 34 - .../uvicorn/lifespan/__init__.py | 0 .../Lib/site-packages/uvicorn/lifespan/off.py | 17 - .../Lib/site-packages/uvicorn/lifespan/on.py | 137 - .../venv/Lib/site-packages/uvicorn/logging.py | 117 - .../site-packages/uvicorn/loops/__init__.py | 0 .../site-packages/uvicorn/loops/asyncio.py | 11 - .../Lib/site-packages/uvicorn/loops/auto.py | 17 - .../Lib/site-packages/uvicorn/loops/uvloop.py | 10 - server/venv/Lib/site-packages/uvicorn/main.py | 644 - .../uvicorn/middleware/__init__.py | 0 .../site-packages/uvicorn/middleware/asgi2.py | 15 - .../uvicorn/middleware/message_logger.py | 87 - .../uvicorn/middleware/proxy_headers.py | 180 - .../site-packages/uvicorn/middleware/wsgi.py | 199 - .../uvicorn/protocols/__init__.py | 0 .../uvicorn/protocols/http/__init__.py | 0 .../uvicorn/protocols/http/auto.py | 15 - .../uvicorn/protocols/http/flow_control.py | 54 - .../uvicorn/protocols/http/h11_impl.py | 544 - .../uvicorn/protocols/http/httptools_impl.py | 576 - .../site-packages/uvicorn/protocols/utils.py | 62 - .../uvicorn/protocols/websockets/__init__.py | 0 .../uvicorn/protocols/websockets/auto.py | 21 - .../protocols/websockets/websockets_impl.py | 372 - .../websockets/websockets_sansio_impl.py | 477 - .../protocols/websockets/wsproto_impl.py | 458 - .../venv/Lib/site-packages/uvicorn/py.typed | 1 - .../venv/Lib/site-packages/uvicorn/server.py | 346 - .../uvicorn/supervisors/__init__.py | 16 - .../uvicorn/supervisors/basereload.py | 125 - .../uvicorn/supervisors/multiprocess.py | 223 - .../uvicorn/supervisors/statreload.py | 52 - .../uvicorn/supervisors/watchfilesreload.py | 86 - .../venv/Lib/site-packages/uvicorn/workers.py | 111 - .../watchfiles-1.2.0.dist-info/INSTALLER | 1 - .../watchfiles-1.2.0.dist-info/METADATA | 148 - .../watchfiles-1.2.0.dist-info/RECORD | 25 - .../watchfiles-1.2.0.dist-info/WHEEL | 4 - .../entry_points.txt | 2 - .../licenses/LICENSE | 21 - .../watchfiles_rust_notify.cyclonedx.json | 1112 - .../Lib/site-packages/watchfiles/__init__.py | 17 - .../Lib/site-packages/watchfiles/__main__.py | 4 - .../_rust_notify.cp313-win_amd64.pyd | Bin 635392 -> 0 bytes .../site-packages/watchfiles/_rust_notify.pyi | 111 - .../venv/Lib/site-packages/watchfiles/cli.py | 225 - .../Lib/site-packages/watchfiles/filters.py | 150 - .../venv/Lib/site-packages/watchfiles/main.py | 374 - .../Lib/site-packages/watchfiles/py.typed | 1 - .../venv/Lib/site-packages/watchfiles/run.py | 439 - .../Lib/site-packages/watchfiles/version.py | 5 - .../websockets-16.0.dist-info/INSTALLER | 1 - .../websockets-16.0.dist-info/METADATA | 179 - .../websockets-16.0.dist-info/RECORD | 108 - .../websockets-16.0.dist-info/WHEEL | 5 - .../entry_points.txt | 2 - .../licenses/LICENSE | 24 - .../websockets-16.0.dist-info/top_level.txt | 1 - .../Lib/site-packages/websockets/__init__.py | 236 - .../Lib/site-packages/websockets/__main__.py | 5 - .../websockets/asyncio/__init__.py | 0 .../websockets/asyncio/async_timeout.py | 282 - .../websockets/asyncio/client.py | 804 - .../websockets/asyncio/compatibility.py | 30 - .../websockets/asyncio/connection.py | 1247 -- .../websockets/asyncio/messages.py | 316 - .../websockets/asyncio/router.py | 219 - .../websockets/asyncio/server.py | 997 - .../venv/Lib/site-packages/websockets/auth.py | 18 - .../venv/Lib/site-packages/websockets/cli.py | 178 - .../Lib/site-packages/websockets/client.py | 391 - .../site-packages/websockets/connection.py | 12 - .../websockets/datastructures.py | 183 - .../site-packages/websockets/exceptions.py | 473 - .../websockets/extensions/__init__.py | 4 - .../websockets/extensions/base.py | 123 - .../extensions/permessage_deflate.py | 699 - .../Lib/site-packages/websockets/frames.py | 431 - .../Lib/site-packages/websockets/headers.py | 586 - .../venv/Lib/site-packages/websockets/http.py | 20 - .../Lib/site-packages/websockets/http11.py | 438 - .../Lib/site-packages/websockets/imports.py | 100 - .../websockets/legacy/__init__.py | 11 - .../site-packages/websockets/legacy/auth.py | 190 - .../site-packages/websockets/legacy/client.py | 703 - .../websockets/legacy/exceptions.py | 71 - .../websockets/legacy/framing.py | 224 - .../websockets/legacy/handshake.py | 158 - .../site-packages/websockets/legacy/http.py | 201 - .../websockets/legacy/protocol.py | 1635 -- .../site-packages/websockets/legacy/server.py | 1191 -- .../Lib/site-packages/websockets/protocol.py | 768 - .../Lib/site-packages/websockets/proxy.py | 150 - .../Lib/site-packages/websockets/py.typed | 0 .../Lib/site-packages/websockets/server.py | 589 - .../Lib/site-packages/websockets/speedups.c | 229 - .../websockets/speedups.cp313-win_amd64.pyd | Bin 11776 -> 0 bytes .../Lib/site-packages/websockets/speedups.pyi | 3 - .../Lib/site-packages/websockets/streams.py | 151 - .../site-packages/websockets/sync/__init__.py | 0 .../site-packages/websockets/sync/client.py | 633 - .../websockets/sync/connection.py | 1078 - .../site-packages/websockets/sync/messages.py | 348 - .../site-packages/websockets/sync/router.py | 213 - .../site-packages/websockets/sync/server.py | 765 - .../site-packages/websockets/sync/utils.py | 45 - .../Lib/site-packages/websockets/typing.py | 75 - .../venv/Lib/site-packages/websockets/uri.py | 107 - .../Lib/site-packages/websockets/utils.py | 53 - .../Lib/site-packages/websockets/version.py | 92 - server/venv/Lib/site-packages/xpprof64.dll | Bin 64640 -> 0 bytes .../venv/Lib/site-packages/yaml/__init__.py | 390 - .../yaml/_yaml.cp313-win_amd64.pyd | Bin 253952 -> 0 bytes .../venv/Lib/site-packages/yaml/composer.py | 139 - .../Lib/site-packages/yaml/constructor.py | 748 - server/venv/Lib/site-packages/yaml/cyaml.py | 101 - server/venv/Lib/site-packages/yaml/dumper.py | 62 - server/venv/Lib/site-packages/yaml/emitter.py | 1137 -- server/venv/Lib/site-packages/yaml/error.py | 75 - server/venv/Lib/site-packages/yaml/events.py | 86 - server/venv/Lib/site-packages/yaml/loader.py | 63 - server/venv/Lib/site-packages/yaml/nodes.py | 49 - server/venv/Lib/site-packages/yaml/parser.py | 589 - server/venv/Lib/site-packages/yaml/reader.py | 185 - .../Lib/site-packages/yaml/representer.py | 389 - .../venv/Lib/site-packages/yaml/resolver.py | 227 - server/venv/Lib/site-packages/yaml/scanner.py | 1435 -- .../venv/Lib/site-packages/yaml/serializer.py | 111 - server/venv/Lib/site-packages/yaml/tokens.py | 104 - server/venv/Scripts/Activate.ps1 | 248 - server/venv/Scripts/activate | 76 - server/venv/Scripts/activate.bat | 34 - server/venv/Scripts/activate.fish | 69 - server/venv/Scripts/deactivate.bat | 22 - server/venv/Scripts/dotenv.exe | Bin 108461 -> 0 bytes server/venv/Scripts/fastapi.exe | Bin 108459 -> 0 bytes server/venv/Scripts/idna.exe | Bin 108456 -> 0 bytes server/venv/Scripts/pip.exe | Bin 108470 -> 0 bytes server/venv/Scripts/pip3.13.exe | Bin 108470 -> 0 bytes server/venv/Scripts/pip3.exe | Bin 108470 -> 0 bytes server/venv/Scripts/python.exe | Bin 255320 -> 0 bytes server/venv/Scripts/pythonw.exe | Bin 251736 -> 0 bytes server/venv/Scripts/uvicorn.exe | Bin 108460 -> 0 bytes server/venv/Scripts/watchfiles.exe | Bin 108460 -> 0 bytes server/venv/Scripts/websockets.exe | Bin 108462 -> 0 bytes server/venv/pyvenv.cfg | 5 - 1179 files changed, 365750 deletions(-) delete mode 100644 server/venv/Lib/site-packages/_mysql_connector.cp313-win_amd64.pyd delete mode 100644 server/venv/Lib/site-packages/_yaml/__init__.py delete mode 100644 server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/entry_points.txt delete mode 100644 server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/licenses/LICENSE delete mode 100644 server/venv/Lib/site-packages/annotated_doc/__init__.py delete mode 100644 server/venv/Lib/site-packages/annotated_doc/main.py delete mode 100644 server/venv/Lib/site-packages/annotated_doc/py.typed delete mode 100644 server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/licenses/LICENSE delete mode 100644 server/venv/Lib/site-packages/annotated_types/__init__.py delete mode 100644 server/venv/Lib/site-packages/annotated_types/py.typed delete mode 100644 server/venv/Lib/site-packages/annotated_types/test_cases.py delete mode 100644 server/venv/Lib/site-packages/anyio-4.14.0.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/anyio-4.14.0.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/anyio-4.14.0.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/anyio-4.14.0.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/anyio-4.14.0.dist-info/entry_points.txt delete mode 100644 server/venv/Lib/site-packages/anyio-4.14.0.dist-info/licenses/LICENSE delete mode 100644 server/venv/Lib/site-packages/anyio-4.14.0.dist-info/top_level.txt delete mode 100644 server/venv/Lib/site-packages/anyio/__init__.py delete mode 100644 server/venv/Lib/site-packages/anyio/_backends/__init__.py delete mode 100644 server/venv/Lib/site-packages/anyio/_backends/_asyncio.py delete mode 100644 server/venv/Lib/site-packages/anyio/_backends/_trio.py delete mode 100644 server/venv/Lib/site-packages/anyio/_core/__init__.py delete mode 100644 server/venv/Lib/site-packages/anyio/_core/_asyncio_selector_thread.py delete mode 100644 server/venv/Lib/site-packages/anyio/_core/_contextmanagers.py delete mode 100644 server/venv/Lib/site-packages/anyio/_core/_eventloop.py delete mode 100644 server/venv/Lib/site-packages/anyio/_core/_exceptions.py delete mode 100644 server/venv/Lib/site-packages/anyio/_core/_fileio.py delete mode 100644 server/venv/Lib/site-packages/anyio/_core/_resources.py delete mode 100644 server/venv/Lib/site-packages/anyio/_core/_signals.py delete mode 100644 server/venv/Lib/site-packages/anyio/_core/_sockets.py delete mode 100644 server/venv/Lib/site-packages/anyio/_core/_streams.py delete mode 100644 server/venv/Lib/site-packages/anyio/_core/_subprocesses.py delete mode 100644 server/venv/Lib/site-packages/anyio/_core/_synchronization.py delete mode 100644 server/venv/Lib/site-packages/anyio/_core/_tasks.py delete mode 100644 server/venv/Lib/site-packages/anyio/_core/_tempfile.py delete mode 100644 server/venv/Lib/site-packages/anyio/_core/_testing.py delete mode 100644 server/venv/Lib/site-packages/anyio/_core/_typedattr.py delete mode 100644 server/venv/Lib/site-packages/anyio/abc/__init__.py delete mode 100644 server/venv/Lib/site-packages/anyio/abc/_eventloop.py delete mode 100644 server/venv/Lib/site-packages/anyio/abc/_resources.py delete mode 100644 server/venv/Lib/site-packages/anyio/abc/_sockets.py delete mode 100644 server/venv/Lib/site-packages/anyio/abc/_streams.py delete mode 100644 server/venv/Lib/site-packages/anyio/abc/_subprocesses.py delete mode 100644 server/venv/Lib/site-packages/anyio/abc/_tasks.py delete mode 100644 server/venv/Lib/site-packages/anyio/abc/_testing.py delete mode 100644 server/venv/Lib/site-packages/anyio/from_thread.py delete mode 100644 server/venv/Lib/site-packages/anyio/functools.py delete mode 100644 server/venv/Lib/site-packages/anyio/itertools.py delete mode 100644 server/venv/Lib/site-packages/anyio/lowlevel.py delete mode 100644 server/venv/Lib/site-packages/anyio/py.typed delete mode 100644 server/venv/Lib/site-packages/anyio/pytest_plugin.py delete mode 100644 server/venv/Lib/site-packages/anyio/streams/__init__.py delete mode 100644 server/venv/Lib/site-packages/anyio/streams/buffered.py delete mode 100644 server/venv/Lib/site-packages/anyio/streams/file.py delete mode 100644 server/venv/Lib/site-packages/anyio/streams/memory.py delete mode 100644 server/venv/Lib/site-packages/anyio/streams/stapled.py delete mode 100644 server/venv/Lib/site-packages/anyio/streams/text.py delete mode 100644 server/venv/Lib/site-packages/anyio/streams/tls.py delete mode 100644 server/venv/Lib/site-packages/anyio/to_interpreter.py delete mode 100644 server/venv/Lib/site-packages/anyio/to_process.py delete mode 100644 server/venv/Lib/site-packages/anyio/to_thread.py delete mode 100644 server/venv/Lib/site-packages/click-8.4.1.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/click-8.4.1.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/click-8.4.1.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/click-8.4.1.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/click-8.4.1.dist-info/licenses/LICENSE.txt delete mode 100644 server/venv/Lib/site-packages/click/__init__.py delete mode 100644 server/venv/Lib/site-packages/click/_compat.py delete mode 100644 server/venv/Lib/site-packages/click/_termui_impl.py delete mode 100644 server/venv/Lib/site-packages/click/_textwrap.py delete mode 100644 server/venv/Lib/site-packages/click/_utils.py delete mode 100644 server/venv/Lib/site-packages/click/_winconsole.py delete mode 100644 server/venv/Lib/site-packages/click/core.py delete mode 100644 server/venv/Lib/site-packages/click/decorators.py delete mode 100644 server/venv/Lib/site-packages/click/exceptions.py delete mode 100644 server/venv/Lib/site-packages/click/formatting.py delete mode 100644 server/venv/Lib/site-packages/click/globals.py delete mode 100644 server/venv/Lib/site-packages/click/parser.py delete mode 100644 server/venv/Lib/site-packages/click/py.typed delete mode 100644 server/venv/Lib/site-packages/click/shell_completion.py delete mode 100644 server/venv/Lib/site-packages/click/termui.py delete mode 100644 server/venv/Lib/site-packages/click/testing.py delete mode 100644 server/venv/Lib/site-packages/click/types.py delete mode 100644 server/venv/Lib/site-packages/click/utils.py delete mode 100644 server/venv/Lib/site-packages/colorama-0.4.6.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/colorama-0.4.6.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/colorama-0.4.6.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/colorama-0.4.6.dist-info/licenses/LICENSE.txt delete mode 100644 server/venv/Lib/site-packages/colorama/__init__.py delete mode 100644 server/venv/Lib/site-packages/colorama/ansi.py delete mode 100644 server/venv/Lib/site-packages/colorama/ansitowin32.py delete mode 100644 server/venv/Lib/site-packages/colorama/initialise.py delete mode 100644 server/venv/Lib/site-packages/colorama/tests/__init__.py delete mode 100644 server/venv/Lib/site-packages/colorama/tests/ansi_test.py delete mode 100644 server/venv/Lib/site-packages/colorama/tests/ansitowin32_test.py delete mode 100644 server/venv/Lib/site-packages/colorama/tests/initialise_test.py delete mode 100644 server/venv/Lib/site-packages/colorama/tests/isatty_test.py delete mode 100644 server/venv/Lib/site-packages/colorama/tests/utils.py delete mode 100644 server/venv/Lib/site-packages/colorama/tests/winterm_test.py delete mode 100644 server/venv/Lib/site-packages/colorama/win32.py delete mode 100644 server/venv/Lib/site-packages/colorama/winterm.py delete mode 100644 server/venv/Lib/site-packages/comerr64.dll delete mode 100644 server/venv/Lib/site-packages/dotenv/__init__.py delete mode 100644 server/venv/Lib/site-packages/dotenv/__main__.py delete mode 100644 server/venv/Lib/site-packages/dotenv/cli.py delete mode 100644 server/venv/Lib/site-packages/dotenv/ipython.py delete mode 100644 server/venv/Lib/site-packages/dotenv/main.py delete mode 100644 server/venv/Lib/site-packages/dotenv/parser.py delete mode 100644 server/venv/Lib/site-packages/dotenv/py.typed delete mode 100644 server/venv/Lib/site-packages/dotenv/variables.py delete mode 100644 server/venv/Lib/site-packages/dotenv/version.py delete mode 100644 server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/REQUESTED delete mode 100644 server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/entry_points.txt delete mode 100644 server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/licenses/LICENSE delete mode 100644 server/venv/Lib/site-packages/fastapi/__init__.py delete mode 100644 server/venv/Lib/site-packages/fastapi/__main__.py delete mode 100644 server/venv/Lib/site-packages/fastapi/_compat/__init__.py delete mode 100644 server/venv/Lib/site-packages/fastapi/_compat/shared.py delete mode 100644 server/venv/Lib/site-packages/fastapi/_compat/v2.py delete mode 100644 server/venv/Lib/site-packages/fastapi/applications.py delete mode 100644 server/venv/Lib/site-packages/fastapi/background.py delete mode 100644 server/venv/Lib/site-packages/fastapi/cli.py delete mode 100644 server/venv/Lib/site-packages/fastapi/concurrency.py delete mode 100644 server/venv/Lib/site-packages/fastapi/datastructures.py delete mode 100644 server/venv/Lib/site-packages/fastapi/dependencies/__init__.py delete mode 100644 server/venv/Lib/site-packages/fastapi/dependencies/models.py delete mode 100644 server/venv/Lib/site-packages/fastapi/dependencies/utils.py delete mode 100644 server/venv/Lib/site-packages/fastapi/encoders.py delete mode 100644 server/venv/Lib/site-packages/fastapi/exception_handlers.py delete mode 100644 server/venv/Lib/site-packages/fastapi/exceptions.py delete mode 100644 server/venv/Lib/site-packages/fastapi/logger.py delete mode 100644 server/venv/Lib/site-packages/fastapi/middleware/__init__.py delete mode 100644 server/venv/Lib/site-packages/fastapi/middleware/asyncexitstack.py delete mode 100644 server/venv/Lib/site-packages/fastapi/middleware/cors.py delete mode 100644 server/venv/Lib/site-packages/fastapi/middleware/gzip.py delete mode 100644 server/venv/Lib/site-packages/fastapi/middleware/httpsredirect.py delete mode 100644 server/venv/Lib/site-packages/fastapi/middleware/trustedhost.py delete mode 100644 server/venv/Lib/site-packages/fastapi/middleware/wsgi.py delete mode 100644 server/venv/Lib/site-packages/fastapi/openapi/__init__.py delete mode 100644 server/venv/Lib/site-packages/fastapi/openapi/constants.py delete mode 100644 server/venv/Lib/site-packages/fastapi/openapi/docs.py delete mode 100644 server/venv/Lib/site-packages/fastapi/openapi/models.py delete mode 100644 server/venv/Lib/site-packages/fastapi/openapi/utils.py delete mode 100644 server/venv/Lib/site-packages/fastapi/param_functions.py delete mode 100644 server/venv/Lib/site-packages/fastapi/params.py delete mode 100644 server/venv/Lib/site-packages/fastapi/py.typed delete mode 100644 server/venv/Lib/site-packages/fastapi/requests.py delete mode 100644 server/venv/Lib/site-packages/fastapi/responses.py delete mode 100644 server/venv/Lib/site-packages/fastapi/routing.py delete mode 100644 server/venv/Lib/site-packages/fastapi/security/__init__.py delete mode 100644 server/venv/Lib/site-packages/fastapi/security/api_key.py delete mode 100644 server/venv/Lib/site-packages/fastapi/security/base.py delete mode 100644 server/venv/Lib/site-packages/fastapi/security/http.py delete mode 100644 server/venv/Lib/site-packages/fastapi/security/oauth2.py delete mode 100644 server/venv/Lib/site-packages/fastapi/security/open_id_connect_url.py delete mode 100644 server/venv/Lib/site-packages/fastapi/security/utils.py delete mode 100644 server/venv/Lib/site-packages/fastapi/sse.py delete mode 100644 server/venv/Lib/site-packages/fastapi/staticfiles.py delete mode 100644 server/venv/Lib/site-packages/fastapi/templating.py delete mode 100644 server/venv/Lib/site-packages/fastapi/testclient.py delete mode 100644 server/venv/Lib/site-packages/fastapi/types.py delete mode 100644 server/venv/Lib/site-packages/fastapi/utils.py delete mode 100644 server/venv/Lib/site-packages/fastapi/websockets.py delete mode 100644 server/venv/Lib/site-packages/gssapi64.dll delete mode 100644 server/venv/Lib/site-packages/h11-0.16.0.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/h11-0.16.0.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/h11-0.16.0.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/h11-0.16.0.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/h11-0.16.0.dist-info/licenses/LICENSE.txt delete mode 100644 server/venv/Lib/site-packages/h11-0.16.0.dist-info/top_level.txt delete mode 100644 server/venv/Lib/site-packages/h11/__init__.py delete mode 100644 server/venv/Lib/site-packages/h11/_abnf.py delete mode 100644 server/venv/Lib/site-packages/h11/_connection.py delete mode 100644 server/venv/Lib/site-packages/h11/_events.py delete mode 100644 server/venv/Lib/site-packages/h11/_headers.py delete mode 100644 server/venv/Lib/site-packages/h11/_readers.py delete mode 100644 server/venv/Lib/site-packages/h11/_receivebuffer.py delete mode 100644 server/venv/Lib/site-packages/h11/_state.py delete mode 100644 server/venv/Lib/site-packages/h11/_util.py delete mode 100644 server/venv/Lib/site-packages/h11/_version.py delete mode 100644 server/venv/Lib/site-packages/h11/_writers.py delete mode 100644 server/venv/Lib/site-packages/h11/py.typed delete mode 100644 server/venv/Lib/site-packages/httptools-0.8.0.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/httptools-0.8.0.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/httptools-0.8.0.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/httptools-0.8.0.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/httptools-0.8.0.dist-info/licenses/LICENSE delete mode 100644 server/venv/Lib/site-packages/httptools-0.8.0.dist-info/licenses/vendor/http-parser/LICENSE-MIT delete mode 100644 server/venv/Lib/site-packages/httptools-0.8.0.dist-info/licenses/vendor/llhttp/LICENSE delete mode 100644 server/venv/Lib/site-packages/httptools-0.8.0.dist-info/top_level.txt delete mode 100644 server/venv/Lib/site-packages/httptools/__init__.py delete mode 100644 server/venv/Lib/site-packages/httptools/_version.py delete mode 100644 server/venv/Lib/site-packages/httptools/parser/__init__.py delete mode 100644 server/venv/Lib/site-packages/httptools/parser/cparser.pxd delete mode 100644 server/venv/Lib/site-packages/httptools/parser/errors.py delete mode 100644 server/venv/Lib/site-packages/httptools/parser/parser.cp313-win_amd64.pyd delete mode 100644 server/venv/Lib/site-packages/httptools/parser/parser.pyi delete mode 100644 server/venv/Lib/site-packages/httptools/parser/parser.pyx delete mode 100644 server/venv/Lib/site-packages/httptools/parser/protocol.py delete mode 100644 server/venv/Lib/site-packages/httptools/parser/python.pxd delete mode 100644 server/venv/Lib/site-packages/httptools/parser/url_cparser.pxd delete mode 100644 server/venv/Lib/site-packages/httptools/parser/url_parser.cp313-win_amd64.pyd delete mode 100644 server/venv/Lib/site-packages/httptools/parser/url_parser.pyi delete mode 100644 server/venv/Lib/site-packages/httptools/parser/url_parser.pyx delete mode 100644 server/venv/Lib/site-packages/httptools/py.typed delete mode 100644 server/venv/Lib/site-packages/idna-3.18.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/idna-3.18.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/idna-3.18.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/idna-3.18.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/idna-3.18.dist-info/entry_points.txt delete mode 100644 server/venv/Lib/site-packages/idna-3.18.dist-info/licenses/LICENSE.md delete mode 100644 server/venv/Lib/site-packages/idna/__init__.py delete mode 100644 server/venv/Lib/site-packages/idna/__main__.py delete mode 100644 server/venv/Lib/site-packages/idna/cli.py delete mode 100644 server/venv/Lib/site-packages/idna/codec.py delete mode 100644 server/venv/Lib/site-packages/idna/compat.py delete mode 100644 server/venv/Lib/site-packages/idna/core.py delete mode 100644 server/venv/Lib/site-packages/idna/idnadata.py delete mode 100644 server/venv/Lib/site-packages/idna/intranges.py delete mode 100644 server/venv/Lib/site-packages/idna/package_data.py delete mode 100644 server/venv/Lib/site-packages/idna/py.typed delete mode 100644 server/venv/Lib/site-packages/idna/uts46data.py delete mode 100644 server/venv/Lib/site-packages/k5sprt64.dll delete mode 100644 server/venv/Lib/site-packages/krb5_64.dll delete mode 100644 server/venv/Lib/site-packages/krbcc64.dll delete mode 100644 server/venv/Lib/site-packages/libcrypto-3-x64.dll delete mode 100644 server/venv/Lib/site-packages/libmysql.dll delete mode 100644 server/venv/Lib/site-packages/libsasl.dll delete mode 100644 server/venv/Lib/site-packages/libssl-3-x64.dll delete mode 100644 server/venv/Lib/site-packages/mysql/__init__.py delete mode 100644 server/venv/Lib/site-packages/mysql/ai/__init__.py delete mode 100644 server/venv/Lib/site-packages/mysql/ai/genai/__init__.py delete mode 100644 server/venv/Lib/site-packages/mysql/ai/genai/embedding.py delete mode 100644 server/venv/Lib/site-packages/mysql/ai/genai/generation.py delete mode 100644 server/venv/Lib/site-packages/mysql/ai/genai/vector_store.py delete mode 100644 server/venv/Lib/site-packages/mysql/ai/ml/__init__.py delete mode 100644 server/venv/Lib/site-packages/mysql/ai/ml/base.py delete mode 100644 server/venv/Lib/site-packages/mysql/ai/ml/classifier.py delete mode 100644 server/venv/Lib/site-packages/mysql/ai/ml/model.py delete mode 100644 server/venv/Lib/site-packages/mysql/ai/ml/outlier.py delete mode 100644 server/venv/Lib/site-packages/mysql/ai/ml/regressor.py delete mode 100644 server/venv/Lib/site-packages/mysql/ai/ml/transformer.py delete mode 100644 server/venv/Lib/site-packages/mysql/ai/utils/__init__.py delete mode 100644 server/venv/Lib/site-packages/mysql/ai/utils/atomic_cursor.py delete mode 100644 server/venv/Lib/site-packages/mysql/ai/utils/dependencies.py delete mode 100644 server/venv/Lib/site-packages/mysql/ai/utils/utils.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/__init__.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/_decorating.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/_scripting.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/abstracts.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/__init__.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/_decorating.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/abstracts.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/authentication.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/charsets.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/connection.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/cursor.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/logger.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/network.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/plugins/__init__.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/plugins/authentication_kerberos_client.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/plugins/authentication_ldap_sasl_client.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/plugins/authentication_oci_client.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/plugins/authentication_openid_connect_client.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/plugins/authentication_webauthn_client.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/plugins/caching_sha2_password.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/plugins/mysql_clear_password.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/plugins/mysql_native_password.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/plugins/sha256_password.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/pooling.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/protocol.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/py.typed delete mode 100644 server/venv/Lib/site-packages/mysql/connector/aio/utils.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/authentication.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/charsets.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/connection.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/connection_cext.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/constants.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/conversion.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/cursor.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/cursor_cext.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/custom_types.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/dbapi.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/django/__init__.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/django/base.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/django/client.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/django/compiler.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/django/creation.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/django/features.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/django/introspection.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/django/operations.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/django/schema.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/django/validation.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/errorcode.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/errors.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/locales/__init__.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/locales/eng/__init__.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/locales/eng/client_error.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/logger.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/network.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/opentelemetry/__init__.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/opentelemetry/constants.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/opentelemetry/context_propagation.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/opentelemetry/instrumentation.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/optionfiles.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/plugins/__init__.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/plugins/authentication_kerberos_client.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/plugins/authentication_ldap_sasl_client.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/plugins/authentication_oci_client.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/plugins/authentication_openid_connect_client.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/plugins/authentication_webauthn_client.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/plugins/caching_sha2_password.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/plugins/mysql_clear_password.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/plugins/mysql_native_password.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/plugins/sha256_password.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/pooling.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/protocol.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/py.typed delete mode 100644 server/venv/Lib/site-packages/mysql/connector/tls_ciphers.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/types.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/utils.py delete mode 100644 server/venv/Lib/site-packages/mysql/connector/version.py delete mode 100644 server/venv/Lib/site-packages/mysql/vendor/libcrypto-3-x64.dll delete mode 100644 server/venv/Lib/site-packages/mysql/vendor/libsasl.dll delete mode 100644 server/venv/Lib/site-packages/mysql/vendor/libssl-3-x64.dll delete mode 100644 server/venv/Lib/site-packages/mysql/vendor/plugin/authentication_kerberos_client.dll delete mode 100644 server/venv/Lib/site-packages/mysql/vendor/plugin/authentication_ldap_sasl_client.dll delete mode 100644 server/venv/Lib/site-packages/mysql/vendor/plugin/authentication_oci_client.dll delete mode 100644 server/venv/Lib/site-packages/mysql/vendor/plugin/authentication_openid_connect_client.dll delete mode 100644 server/venv/Lib/site-packages/mysql/vendor/plugin/authentication_webauthn_client.dll delete mode 100644 server/venv/Lib/site-packages/mysql/vendor/plugin/mysql_native_password.dll delete mode 100644 server/venv/Lib/site-packages/mysql_connector_python-9.7.0.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/mysql_connector_python-9.7.0.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/mysql_connector_python-9.7.0.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/mysql_connector_python-9.7.0.dist-info/REQUESTED delete mode 100644 server/venv/Lib/site-packages/mysql_connector_python-9.7.0.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/mysql_connector_python-9.7.0.dist-info/licenses/LICENSE.txt delete mode 100644 server/venv/Lib/site-packages/mysql_connector_python-9.7.0.dist-info/top_level.txt delete mode 100644 server/venv/Lib/site-packages/paho/__init__.py delete mode 100644 server/venv/Lib/site-packages/paho/mqtt/__init__.py delete mode 100644 server/venv/Lib/site-packages/paho/mqtt/client.py delete mode 100644 server/venv/Lib/site-packages/paho/mqtt/enums.py delete mode 100644 server/venv/Lib/site-packages/paho/mqtt/matcher.py delete mode 100644 server/venv/Lib/site-packages/paho/mqtt/packettypes.py delete mode 100644 server/venv/Lib/site-packages/paho/mqtt/properties.py delete mode 100644 server/venv/Lib/site-packages/paho/mqtt/publish.py delete mode 100644 server/venv/Lib/site-packages/paho/mqtt/py.typed delete mode 100644 server/venv/Lib/site-packages/paho/mqtt/reasoncodes.py delete mode 100644 server/venv/Lib/site-packages/paho/mqtt/subscribe.py delete mode 100644 server/venv/Lib/site-packages/paho/mqtt/subscribeoptions.py delete mode 100644 server/venv/Lib/site-packages/paho_mqtt-2.1.0.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/paho_mqtt-2.1.0.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/paho_mqtt-2.1.0.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/paho_mqtt-2.1.0.dist-info/REQUESTED delete mode 100644 server/venv/Lib/site-packages/paho_mqtt-2.1.0.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/paho_mqtt-2.1.0.dist-info/licenses/LICENSE.txt delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/REQUESTED delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/entry_points.txt delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/AUTHORS.txt delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/LICENSE.txt delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/cachecontrol/LICENSE.txt delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/certifi/LICENSE delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/dependency_groups/LICENSE.txt delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/distlib/LICENSE.txt delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/distro/LICENSE delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/idna/LICENSE.md delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/msgpack/COPYING delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/packaging/LICENSE delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/packaging/LICENSE.APACHE delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/packaging/LICENSE.BSD delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/pkg_resources/LICENSE delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/platformdirs/LICENSE delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/pygments/LICENSE delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/pyproject_hooks/LICENSE delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/requests/LICENSE delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/resolvelib/LICENSE delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/rich/LICENSE delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/tomli/LICENSE delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/tomli/LICENSE-HEADER delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/tomli_w/LICENSE delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/truststore/LICENSE delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/licenses/src/pip/_vendor/urllib3/LICENSE.txt delete mode 100644 server/venv/Lib/site-packages/pip-25.2.dist-info/top_level.txt delete mode 100644 server/venv/Lib/site-packages/pip/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/__main__.py delete mode 100644 server/venv/Lib/site-packages/pip/__pip-runner__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/build_env.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/cache.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/cli/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/cli/autocompletion.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/cli/base_command.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/cli/cmdoptions.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/cli/command_context.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/cli/index_command.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/cli/main.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/cli/main_parser.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/cli/parser.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/cli/progress_bars.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/cli/req_command.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/cli/spinners.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/cli/status_codes.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/cache.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/check.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/completion.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/configuration.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/debug.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/download.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/freeze.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/hash.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/help.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/index.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/inspect.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/install.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/list.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/lock.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/search.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/show.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/uninstall.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/commands/wheel.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/configuration.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/distributions/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/distributions/base.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/distributions/installed.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/distributions/sdist.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/distributions/wheel.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/exceptions.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/index/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/index/collector.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/index/package_finder.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/index/sources.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/locations/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/locations/_distutils.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/locations/_sysconfig.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/locations/base.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/main.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/metadata/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/metadata/_json.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/metadata/base.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/metadata/importlib/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/metadata/importlib/_compat.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/metadata/importlib/_dists.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/metadata/importlib/_envs.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/metadata/pkg_resources.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/models/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/models/candidate.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/models/direct_url.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/models/format_control.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/models/index.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/models/installation_report.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/models/link.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/models/pylock.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/models/scheme.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/models/search_scope.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/models/selection_prefs.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/models/target_python.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/models/wheel.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/network/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/network/auth.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/network/cache.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/network/download.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/network/lazy_wheel.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/network/session.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/network/utils.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/network/xmlrpc.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/operations/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/operations/build/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/operations/build/build_tracker.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/operations/build/metadata.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/operations/build/metadata_editable.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/operations/build/metadata_legacy.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/operations/build/wheel.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/operations/build/wheel_editable.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/operations/build/wheel_legacy.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/operations/check.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/operations/freeze.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/operations/install/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/operations/install/editable_legacy.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/operations/install/wheel.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/operations/prepare.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/pyproject.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/req/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/req/constructors.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/req/req_dependency_group.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/req/req_file.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/req/req_install.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/req/req_set.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/req/req_uninstall.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/resolution/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/resolution/base.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/resolution/legacy/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/resolution/legacy/resolver.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/base.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/candidates.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/factory.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/provider.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/reporter.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/requirements.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/resolver.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/self_outdated_check.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/_jaraco_text.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/_log.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/appdirs.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/compat.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/compatibility_tags.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/datetime.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/deprecation.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/direct_url_helpers.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/egg_link.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/entrypoints.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/filesystem.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/filetypes.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/glibc.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/hashes.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/logging.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/misc.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/packaging.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/retry.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/setuptools_build.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/subprocess.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/temp_dir.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/unpacking.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/urls.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/virtualenv.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/utils/wheel.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/vcs/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/vcs/bazaar.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/vcs/git.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/vcs/mercurial.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/vcs/subversion.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/vcs/versioncontrol.py delete mode 100644 server/venv/Lib/site-packages/pip/_internal/wheel_builder.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/cachecontrol/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/cachecontrol/_cmd.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/cachecontrol/adapter.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/cachecontrol/cache.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/cachecontrol/controller.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/cachecontrol/filewrapper.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/cachecontrol/heuristics.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/cachecontrol/py.typed delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/cachecontrol/serialize.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/cachecontrol/wrapper.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/certifi/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/certifi/__main__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/certifi/cacert.pem delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/certifi/core.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/certifi/py.typed delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/dependency_groups/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/dependency_groups/__main__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/dependency_groups/_implementation.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/dependency_groups/_lint_dependency_groups.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/dependency_groups/_pip_wrapper.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/dependency_groups/_toml_compat.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/dependency_groups/py.typed delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/distlib/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/distlib/compat.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/distlib/resources.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/distlib/scripts.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/distlib/t32.exe delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/distlib/t64-arm.exe delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/distlib/t64.exe delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/distlib/util.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/distlib/w32.exe delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/distlib/w64-arm.exe delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/distlib/w64.exe delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/distro/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/distro/__main__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/distro/distro.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/distro/py.typed delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/idna/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/idna/codec.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/idna/compat.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/idna/core.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/idna/idnadata.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/idna/intranges.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/idna/package_data.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/idna/py.typed delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/idna/uts46data.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/msgpack/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/msgpack/exceptions.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/msgpack/ext.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/msgpack/fallback.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/packaging/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/packaging/_elffile.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/packaging/_manylinux.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/packaging/_musllinux.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/packaging/_parser.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/packaging/_structures.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/packaging/_tokenizer.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/packaging/licenses/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/packaging/licenses/_spdx.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/packaging/markers.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/packaging/metadata.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/packaging/py.typed delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/packaging/requirements.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/packaging/specifiers.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/packaging/tags.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/packaging/utils.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/packaging/version.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pkg_resources/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/platformdirs/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/platformdirs/__main__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/platformdirs/android.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/platformdirs/api.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/platformdirs/macos.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/platformdirs/py.typed delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/platformdirs/unix.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/platformdirs/version.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/platformdirs/windows.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/__main__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/console.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/filter.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/filters/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/formatter.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/formatters/_mapping.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/lexer.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/lexers/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/lexers/_mapping.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/lexers/python.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/modeline.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/plugin.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/regexopt.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/scanner.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/sphinxext.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/style.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/styles/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/styles/_mapping.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/token.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/unistring.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pygments/util.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_impl.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_in_process/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/py.typed delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/requests/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/requests/__version__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/requests/_internal_utils.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/requests/adapters.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/requests/api.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/requests/auth.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/requests/certs.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/requests/compat.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/requests/cookies.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/requests/exceptions.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/requests/help.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/requests/hooks.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/requests/models.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/requests/packages.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/requests/sessions.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/requests/status_codes.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/requests/structures.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/requests/utils.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/resolvelib/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/resolvelib/providers.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/resolvelib/py.typed delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/resolvelib/reporters.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/resolvelib/resolvers/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/resolvelib/resolvers/abstract.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/resolvelib/resolvers/criterion.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/resolvelib/resolvers/exceptions.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/resolvelib/resolvers/resolution.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/resolvelib/structs.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/__main__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_cell_widths.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_emoji_codes.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_emoji_replace.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_export_format.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_extension.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_fileno.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_inspect.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_log_render.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_loop.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_null_file.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_palettes.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_pick.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_ratio.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_spinners.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_stack.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_timer.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_win32_console.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_windows.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_windows_renderer.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/_wrap.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/abc.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/align.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/ansi.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/bar.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/box.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/cells.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/color.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/color_triplet.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/columns.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/console.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/constrain.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/containers.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/control.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/default_styles.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/diagnose.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/emoji.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/errors.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/file_proxy.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/filesize.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/highlighter.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/json.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/jupyter.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/layout.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/live.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/live_render.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/logging.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/markup.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/measure.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/padding.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/pager.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/palette.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/panel.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/pretty.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/progress.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/progress_bar.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/prompt.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/protocol.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/py.typed delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/region.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/repr.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/rule.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/scope.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/screen.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/segment.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/spinner.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/status.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/style.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/styled.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/syntax.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/table.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/terminal_theme.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/text.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/theme.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/themes.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/traceback.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/rich/tree.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/tomli/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/tomli/_parser.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/tomli/_re.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/tomli/_types.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/tomli/py.typed delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/tomli_w/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/tomli_w/_writer.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/tomli_w/py.typed delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/truststore/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/truststore/_api.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/truststore/_macos.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/truststore/_openssl.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/truststore/_ssl_constants.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/truststore/_windows.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/truststore/py.typed delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/_collections.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/_version.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/connection.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/connectionpool.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/appengine.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/securetransport.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/socks.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/exceptions.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/fields.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/filepost.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/packages/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/weakref_finalize.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/packages/six.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/poolmanager.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/request.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/response.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/util/__init__.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/util/connection.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/util/proxy.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/util/queue.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/util/request.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/util/response.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/util/retry.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssl_.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssl_match_hostname.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssltransport.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/util/timeout.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/util/url.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/urllib3/util/wait.py delete mode 100644 server/venv/Lib/site-packages/pip/_vendor/vendor.txt delete mode 100644 server/venv/Lib/site-packages/pip/py.typed delete mode 100644 server/venv/Lib/site-packages/pydantic-2.13.4.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/pydantic-2.13.4.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/pydantic-2.13.4.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/pydantic-2.13.4.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/pydantic-2.13.4.dist-info/licenses/LICENSE delete mode 100644 server/venv/Lib/site-packages/pydantic/__init__.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/__init__.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_config.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_core_metadata.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_core_utils.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_dataclasses.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_decorators.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_decorators_v1.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_discriminated_union.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_docs_extraction.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_fields.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_forward_ref.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_generate_schema.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_generics.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_git.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_import_utils.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_internal_dataclass.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_known_annotated_metadata.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_mock_val_ser.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_model_construction.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_namespace_utils.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_repr.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_schema_gather.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_schema_generation_shared.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_serializers.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_signature.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_typing_extra.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_utils.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_validate_call.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_internal/_validators.py delete mode 100644 server/venv/Lib/site-packages/pydantic/_migration.py delete mode 100644 server/venv/Lib/site-packages/pydantic/alias_generators.py delete mode 100644 server/venv/Lib/site-packages/pydantic/aliases.py delete mode 100644 server/venv/Lib/site-packages/pydantic/annotated_handlers.py delete mode 100644 server/venv/Lib/site-packages/pydantic/class_validators.py delete mode 100644 server/venv/Lib/site-packages/pydantic/color.py delete mode 100644 server/venv/Lib/site-packages/pydantic/config.py delete mode 100644 server/venv/Lib/site-packages/pydantic/dataclasses.py delete mode 100644 server/venv/Lib/site-packages/pydantic/datetime_parse.py delete mode 100644 server/venv/Lib/site-packages/pydantic/decorator.py delete mode 100644 server/venv/Lib/site-packages/pydantic/deprecated/__init__.py delete mode 100644 server/venv/Lib/site-packages/pydantic/deprecated/class_validators.py delete mode 100644 server/venv/Lib/site-packages/pydantic/deprecated/config.py delete mode 100644 server/venv/Lib/site-packages/pydantic/deprecated/copy_internals.py delete mode 100644 server/venv/Lib/site-packages/pydantic/deprecated/decorator.py delete mode 100644 server/venv/Lib/site-packages/pydantic/deprecated/json.py delete mode 100644 server/venv/Lib/site-packages/pydantic/deprecated/parse.py delete mode 100644 server/venv/Lib/site-packages/pydantic/deprecated/tools.py delete mode 100644 server/venv/Lib/site-packages/pydantic/env_settings.py delete mode 100644 server/venv/Lib/site-packages/pydantic/error_wrappers.py delete mode 100644 server/venv/Lib/site-packages/pydantic/errors.py delete mode 100644 server/venv/Lib/site-packages/pydantic/experimental/__init__.py delete mode 100644 server/venv/Lib/site-packages/pydantic/experimental/arguments_schema.py delete mode 100644 server/venv/Lib/site-packages/pydantic/experimental/missing_sentinel.py delete mode 100644 server/venv/Lib/site-packages/pydantic/experimental/pipeline.py delete mode 100644 server/venv/Lib/site-packages/pydantic/fields.py delete mode 100644 server/venv/Lib/site-packages/pydantic/functional_serializers.py delete mode 100644 server/venv/Lib/site-packages/pydantic/functional_validators.py delete mode 100644 server/venv/Lib/site-packages/pydantic/generics.py delete mode 100644 server/venv/Lib/site-packages/pydantic/json.py delete mode 100644 server/venv/Lib/site-packages/pydantic/json_schema.py delete mode 100644 server/venv/Lib/site-packages/pydantic/main.py delete mode 100644 server/venv/Lib/site-packages/pydantic/mypy.py delete mode 100644 server/venv/Lib/site-packages/pydantic/networks.py delete mode 100644 server/venv/Lib/site-packages/pydantic/parse.py delete mode 100644 server/venv/Lib/site-packages/pydantic/plugin/__init__.py delete mode 100644 server/venv/Lib/site-packages/pydantic/plugin/_loader.py delete mode 100644 server/venv/Lib/site-packages/pydantic/plugin/_schema_validator.py delete mode 100644 server/venv/Lib/site-packages/pydantic/py.typed delete mode 100644 server/venv/Lib/site-packages/pydantic/root_model.py delete mode 100644 server/venv/Lib/site-packages/pydantic/schema.py delete mode 100644 server/venv/Lib/site-packages/pydantic/tools.py delete mode 100644 server/venv/Lib/site-packages/pydantic/type_adapter.py delete mode 100644 server/venv/Lib/site-packages/pydantic/types.py delete mode 100644 server/venv/Lib/site-packages/pydantic/typing.py delete mode 100644 server/venv/Lib/site-packages/pydantic/utils.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/__init__.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/_hypothesis_plugin.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/annotated_types.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/class_validators.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/color.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/config.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/dataclasses.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/datetime_parse.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/decorator.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/env_settings.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/error_wrappers.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/errors.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/fields.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/generics.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/json.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/main.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/mypy.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/networks.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/parse.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/py.typed delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/schema.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/tools.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/types.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/typing.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/utils.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/validators.py delete mode 100644 server/venv/Lib/site-packages/pydantic/v1/version.py delete mode 100644 server/venv/Lib/site-packages/pydantic/validate_call_decorator.py delete mode 100644 server/venv/Lib/site-packages/pydantic/validators.py delete mode 100644 server/venv/Lib/site-packages/pydantic/version.py delete mode 100644 server/venv/Lib/site-packages/pydantic/warnings.py delete mode 100644 server/venv/Lib/site-packages/pydantic_core-2.46.4.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/pydantic_core-2.46.4.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/pydantic_core-2.46.4.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/pydantic_core-2.46.4.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/pydantic_core-2.46.4.dist-info/licenses/LICENSE delete mode 100644 server/venv/Lib/site-packages/pydantic_core-2.46.4.dist-info/sboms/pydantic-core.cyclonedx.json delete mode 100644 server/venv/Lib/site-packages/pydantic_core/__init__.py delete mode 100644 server/venv/Lib/site-packages/pydantic_core/_pydantic_core.cp313-win_amd64.pyd delete mode 100644 server/venv/Lib/site-packages/pydantic_core/_pydantic_core.pyi delete mode 100644 server/venv/Lib/site-packages/pydantic_core/core_schema.py delete mode 100644 server/venv/Lib/site-packages/pydantic_core/py.typed delete mode 100644 server/venv/Lib/site-packages/python_dotenv-1.2.2.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/python_dotenv-1.2.2.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/python_dotenv-1.2.2.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/python_dotenv-1.2.2.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/python_dotenv-1.2.2.dist-info/entry_points.txt delete mode 100644 server/venv/Lib/site-packages/python_dotenv-1.2.2.dist-info/licenses/LICENSE delete mode 100644 server/venv/Lib/site-packages/python_dotenv-1.2.2.dist-info/top_level.txt delete mode 100644 server/venv/Lib/site-packages/pyyaml-6.0.3.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/pyyaml-6.0.3.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/pyyaml-6.0.3.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/pyyaml-6.0.3.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/pyyaml-6.0.3.dist-info/licenses/LICENSE delete mode 100644 server/venv/Lib/site-packages/pyyaml-6.0.3.dist-info/top_level.txt delete mode 100644 server/venv/Lib/site-packages/sasl2/saslGSSAPI.dll delete mode 100644 server/venv/Lib/site-packages/sasl2/saslSCRAM.dll delete mode 100644 server/venv/Lib/site-packages/starlette-1.3.1.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/starlette-1.3.1.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/starlette-1.3.1.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/starlette-1.3.1.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/starlette-1.3.1.dist-info/licenses/LICENSE.md delete mode 100644 server/venv/Lib/site-packages/starlette/__init__.py delete mode 100644 server/venv/Lib/site-packages/starlette/_exception_handler.py delete mode 100644 server/venv/Lib/site-packages/starlette/_utils.py delete mode 100644 server/venv/Lib/site-packages/starlette/applications.py delete mode 100644 server/venv/Lib/site-packages/starlette/authentication.py delete mode 100644 server/venv/Lib/site-packages/starlette/background.py delete mode 100644 server/venv/Lib/site-packages/starlette/concurrency.py delete mode 100644 server/venv/Lib/site-packages/starlette/config.py delete mode 100644 server/venv/Lib/site-packages/starlette/convertors.py delete mode 100644 server/venv/Lib/site-packages/starlette/datastructures.py delete mode 100644 server/venv/Lib/site-packages/starlette/endpoints.py delete mode 100644 server/venv/Lib/site-packages/starlette/exceptions.py delete mode 100644 server/venv/Lib/site-packages/starlette/formparsers.py delete mode 100644 server/venv/Lib/site-packages/starlette/middleware/__init__.py delete mode 100644 server/venv/Lib/site-packages/starlette/middleware/authentication.py delete mode 100644 server/venv/Lib/site-packages/starlette/middleware/base.py delete mode 100644 server/venv/Lib/site-packages/starlette/middleware/cors.py delete mode 100644 server/venv/Lib/site-packages/starlette/middleware/errors.py delete mode 100644 server/venv/Lib/site-packages/starlette/middleware/exceptions.py delete mode 100644 server/venv/Lib/site-packages/starlette/middleware/gzip.py delete mode 100644 server/venv/Lib/site-packages/starlette/middleware/httpsredirect.py delete mode 100644 server/venv/Lib/site-packages/starlette/middleware/sessions.py delete mode 100644 server/venv/Lib/site-packages/starlette/middleware/trustedhost.py delete mode 100644 server/venv/Lib/site-packages/starlette/middleware/wsgi.py delete mode 100644 server/venv/Lib/site-packages/starlette/py.typed delete mode 100644 server/venv/Lib/site-packages/starlette/requests.py delete mode 100644 server/venv/Lib/site-packages/starlette/responses.py delete mode 100644 server/venv/Lib/site-packages/starlette/routing.py delete mode 100644 server/venv/Lib/site-packages/starlette/schemas.py delete mode 100644 server/venv/Lib/site-packages/starlette/staticfiles.py delete mode 100644 server/venv/Lib/site-packages/starlette/status.py delete mode 100644 server/venv/Lib/site-packages/starlette/templating.py delete mode 100644 server/venv/Lib/site-packages/starlette/testclient.py delete mode 100644 server/venv/Lib/site-packages/starlette/types.py delete mode 100644 server/venv/Lib/site-packages/starlette/websockets.py delete mode 100644 server/venv/Lib/site-packages/typing_extensions-4.15.0.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/typing_extensions-4.15.0.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/typing_extensions-4.15.0.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/typing_extensions-4.15.0.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/typing_extensions-4.15.0.dist-info/licenses/LICENSE delete mode 100644 server/venv/Lib/site-packages/typing_extensions.py delete mode 100644 server/venv/Lib/site-packages/typing_inspection-0.4.2.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/typing_inspection-0.4.2.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/typing_inspection-0.4.2.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/typing_inspection-0.4.2.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/typing_inspection-0.4.2.dist-info/licenses/LICENSE delete mode 100644 server/venv/Lib/site-packages/typing_inspection/__init__.py delete mode 100644 server/venv/Lib/site-packages/typing_inspection/introspection.py delete mode 100644 server/venv/Lib/site-packages/typing_inspection/py.typed delete mode 100644 server/venv/Lib/site-packages/typing_inspection/typing_objects.py delete mode 100644 server/venv/Lib/site-packages/typing_inspection/typing_objects.pyi delete mode 100644 server/venv/Lib/site-packages/uvicorn-0.49.0.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/uvicorn-0.49.0.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/uvicorn-0.49.0.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/uvicorn-0.49.0.dist-info/REQUESTED delete mode 100644 server/venv/Lib/site-packages/uvicorn-0.49.0.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/uvicorn-0.49.0.dist-info/entry_points.txt delete mode 100644 server/venv/Lib/site-packages/uvicorn-0.49.0.dist-info/licenses/LICENSE.md delete mode 100644 server/venv/Lib/site-packages/uvicorn/__init__.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/__main__.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/_compat.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/_subprocess.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/_types.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/config.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/importer.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/lifespan/__init__.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/lifespan/off.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/lifespan/on.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/logging.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/loops/__init__.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/loops/asyncio.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/loops/auto.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/loops/uvloop.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/main.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/middleware/__init__.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/middleware/asgi2.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/middleware/message_logger.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/middleware/proxy_headers.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/middleware/wsgi.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/protocols/__init__.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/protocols/http/__init__.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/protocols/http/auto.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/protocols/http/flow_control.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/protocols/http/h11_impl.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/protocols/http/httptools_impl.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/protocols/utils.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/protocols/websockets/__init__.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/protocols/websockets/auto.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/protocols/websockets/websockets_impl.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/protocols/websockets/websockets_sansio_impl.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/protocols/websockets/wsproto_impl.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/py.typed delete mode 100644 server/venv/Lib/site-packages/uvicorn/server.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/supervisors/__init__.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/supervisors/basereload.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/supervisors/multiprocess.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/supervisors/statreload.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/supervisors/watchfilesreload.py delete mode 100644 server/venv/Lib/site-packages/uvicorn/workers.py delete mode 100644 server/venv/Lib/site-packages/watchfiles-1.2.0.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/watchfiles-1.2.0.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/watchfiles-1.2.0.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/watchfiles-1.2.0.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/watchfiles-1.2.0.dist-info/entry_points.txt delete mode 100644 server/venv/Lib/site-packages/watchfiles-1.2.0.dist-info/licenses/LICENSE delete mode 100644 server/venv/Lib/site-packages/watchfiles-1.2.0.dist-info/sboms/watchfiles_rust_notify.cyclonedx.json delete mode 100644 server/venv/Lib/site-packages/watchfiles/__init__.py delete mode 100644 server/venv/Lib/site-packages/watchfiles/__main__.py delete mode 100644 server/venv/Lib/site-packages/watchfiles/_rust_notify.cp313-win_amd64.pyd delete mode 100644 server/venv/Lib/site-packages/watchfiles/_rust_notify.pyi delete mode 100644 server/venv/Lib/site-packages/watchfiles/cli.py delete mode 100644 server/venv/Lib/site-packages/watchfiles/filters.py delete mode 100644 server/venv/Lib/site-packages/watchfiles/main.py delete mode 100644 server/venv/Lib/site-packages/watchfiles/py.typed delete mode 100644 server/venv/Lib/site-packages/watchfiles/run.py delete mode 100644 server/venv/Lib/site-packages/watchfiles/version.py delete mode 100644 server/venv/Lib/site-packages/websockets-16.0.dist-info/INSTALLER delete mode 100644 server/venv/Lib/site-packages/websockets-16.0.dist-info/METADATA delete mode 100644 server/venv/Lib/site-packages/websockets-16.0.dist-info/RECORD delete mode 100644 server/venv/Lib/site-packages/websockets-16.0.dist-info/WHEEL delete mode 100644 server/venv/Lib/site-packages/websockets-16.0.dist-info/entry_points.txt delete mode 100644 server/venv/Lib/site-packages/websockets-16.0.dist-info/licenses/LICENSE delete mode 100644 server/venv/Lib/site-packages/websockets-16.0.dist-info/top_level.txt delete mode 100644 server/venv/Lib/site-packages/websockets/__init__.py delete mode 100644 server/venv/Lib/site-packages/websockets/__main__.py delete mode 100644 server/venv/Lib/site-packages/websockets/asyncio/__init__.py delete mode 100644 server/venv/Lib/site-packages/websockets/asyncio/async_timeout.py delete mode 100644 server/venv/Lib/site-packages/websockets/asyncio/client.py delete mode 100644 server/venv/Lib/site-packages/websockets/asyncio/compatibility.py delete mode 100644 server/venv/Lib/site-packages/websockets/asyncio/connection.py delete mode 100644 server/venv/Lib/site-packages/websockets/asyncio/messages.py delete mode 100644 server/venv/Lib/site-packages/websockets/asyncio/router.py delete mode 100644 server/venv/Lib/site-packages/websockets/asyncio/server.py delete mode 100644 server/venv/Lib/site-packages/websockets/auth.py delete mode 100644 server/venv/Lib/site-packages/websockets/cli.py delete mode 100644 server/venv/Lib/site-packages/websockets/client.py delete mode 100644 server/venv/Lib/site-packages/websockets/connection.py delete mode 100644 server/venv/Lib/site-packages/websockets/datastructures.py delete mode 100644 server/venv/Lib/site-packages/websockets/exceptions.py delete mode 100644 server/venv/Lib/site-packages/websockets/extensions/__init__.py delete mode 100644 server/venv/Lib/site-packages/websockets/extensions/base.py delete mode 100644 server/venv/Lib/site-packages/websockets/extensions/permessage_deflate.py delete mode 100644 server/venv/Lib/site-packages/websockets/frames.py delete mode 100644 server/venv/Lib/site-packages/websockets/headers.py delete mode 100644 server/venv/Lib/site-packages/websockets/http.py delete mode 100644 server/venv/Lib/site-packages/websockets/http11.py delete mode 100644 server/venv/Lib/site-packages/websockets/imports.py delete mode 100644 server/venv/Lib/site-packages/websockets/legacy/__init__.py delete mode 100644 server/venv/Lib/site-packages/websockets/legacy/auth.py delete mode 100644 server/venv/Lib/site-packages/websockets/legacy/client.py delete mode 100644 server/venv/Lib/site-packages/websockets/legacy/exceptions.py delete mode 100644 server/venv/Lib/site-packages/websockets/legacy/framing.py delete mode 100644 server/venv/Lib/site-packages/websockets/legacy/handshake.py delete mode 100644 server/venv/Lib/site-packages/websockets/legacy/http.py delete mode 100644 server/venv/Lib/site-packages/websockets/legacy/protocol.py delete mode 100644 server/venv/Lib/site-packages/websockets/legacy/server.py delete mode 100644 server/venv/Lib/site-packages/websockets/protocol.py delete mode 100644 server/venv/Lib/site-packages/websockets/proxy.py delete mode 100644 server/venv/Lib/site-packages/websockets/py.typed delete mode 100644 server/venv/Lib/site-packages/websockets/server.py delete mode 100644 server/venv/Lib/site-packages/websockets/speedups.c delete mode 100644 server/venv/Lib/site-packages/websockets/speedups.cp313-win_amd64.pyd delete mode 100644 server/venv/Lib/site-packages/websockets/speedups.pyi delete mode 100644 server/venv/Lib/site-packages/websockets/streams.py delete mode 100644 server/venv/Lib/site-packages/websockets/sync/__init__.py delete mode 100644 server/venv/Lib/site-packages/websockets/sync/client.py delete mode 100644 server/venv/Lib/site-packages/websockets/sync/connection.py delete mode 100644 server/venv/Lib/site-packages/websockets/sync/messages.py delete mode 100644 server/venv/Lib/site-packages/websockets/sync/router.py delete mode 100644 server/venv/Lib/site-packages/websockets/sync/server.py delete mode 100644 server/venv/Lib/site-packages/websockets/sync/utils.py delete mode 100644 server/venv/Lib/site-packages/websockets/typing.py delete mode 100644 server/venv/Lib/site-packages/websockets/uri.py delete mode 100644 server/venv/Lib/site-packages/websockets/utils.py delete mode 100644 server/venv/Lib/site-packages/websockets/version.py delete mode 100644 server/venv/Lib/site-packages/xpprof64.dll delete mode 100644 server/venv/Lib/site-packages/yaml/__init__.py delete mode 100644 server/venv/Lib/site-packages/yaml/_yaml.cp313-win_amd64.pyd delete mode 100644 server/venv/Lib/site-packages/yaml/composer.py delete mode 100644 server/venv/Lib/site-packages/yaml/constructor.py delete mode 100644 server/venv/Lib/site-packages/yaml/cyaml.py delete mode 100644 server/venv/Lib/site-packages/yaml/dumper.py delete mode 100644 server/venv/Lib/site-packages/yaml/emitter.py delete mode 100644 server/venv/Lib/site-packages/yaml/error.py delete mode 100644 server/venv/Lib/site-packages/yaml/events.py delete mode 100644 server/venv/Lib/site-packages/yaml/loader.py delete mode 100644 server/venv/Lib/site-packages/yaml/nodes.py delete mode 100644 server/venv/Lib/site-packages/yaml/parser.py delete mode 100644 server/venv/Lib/site-packages/yaml/reader.py delete mode 100644 server/venv/Lib/site-packages/yaml/representer.py delete mode 100644 server/venv/Lib/site-packages/yaml/resolver.py delete mode 100644 server/venv/Lib/site-packages/yaml/scanner.py delete mode 100644 server/venv/Lib/site-packages/yaml/serializer.py delete mode 100644 server/venv/Lib/site-packages/yaml/tokens.py delete mode 100644 server/venv/Scripts/Activate.ps1 delete mode 100644 server/venv/Scripts/activate delete mode 100644 server/venv/Scripts/activate.bat delete mode 100644 server/venv/Scripts/activate.fish delete mode 100644 server/venv/Scripts/deactivate.bat delete mode 100644 server/venv/Scripts/dotenv.exe delete mode 100644 server/venv/Scripts/fastapi.exe delete mode 100644 server/venv/Scripts/idna.exe delete mode 100644 server/venv/Scripts/pip.exe delete mode 100644 server/venv/Scripts/pip3.13.exe delete mode 100644 server/venv/Scripts/pip3.exe delete mode 100644 server/venv/Scripts/python.exe delete mode 100644 server/venv/Scripts/pythonw.exe delete mode 100644 server/venv/Scripts/uvicorn.exe delete mode 100644 server/venv/Scripts/watchfiles.exe delete mode 100644 server/venv/Scripts/websockets.exe delete mode 100644 server/venv/pyvenv.cfg diff --git a/server/venv/Lib/site-packages/_mysql_connector.cp313-win_amd64.pyd b/server/venv/Lib/site-packages/_mysql_connector.cp313-win_amd64.pyd deleted file mode 100644 index 311f718c3bfc731005b1e37d3d98333182693c90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 72880 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 (3, 6) else ImportError - raise exc("No module named '_yaml'") -else: - from yaml._yaml import * - import warnings - warnings.warn( - 'The _yaml extension module is now located at yaml._yaml' - ' and its location is subject to change. To use the' - ' LibYAML-based parser and emitter, import from `yaml`:' - ' `from yaml import CLoader as Loader, CDumper as Dumper`.', - DeprecationWarning - ) - del warnings - # Don't `del yaml` here because yaml is actually an existing - # namespace member of _yaml. - -__name__ = '_yaml' -# If the module is top-level (i.e. not a part of any specific package) -# then the attribute should be set to ''. -# https://docs.python.org/3.8/library/types.html -__package__ = '' diff --git a/server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/INSTALLER b/server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/METADATA b/server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/METADATA deleted file mode 100644 index 9bf7a9e..0000000 --- a/server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/METADATA +++ /dev/null @@ -1,145 +0,0 @@ -Metadata-Version: 2.4 -Name: annotated-doc -Version: 0.0.4 -Summary: Document parameters, class attributes, return types, and variables inline, with Annotated. -Author-Email: =?utf-8?q?Sebasti=C3=A1n_Ram=C3=ADrez?= -License-Expression: MIT -License-File: LICENSE -Classifier: Intended Audience :: Information Technology -Classifier: Intended Audience :: System Administrators -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python -Classifier: Topic :: Internet -Classifier: Topic :: Software Development :: Libraries :: Application Frameworks -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Software Development :: Libraries -Classifier: Topic :: Software Development -Classifier: Typing :: Typed -Classifier: Development Status :: 4 - Beta -Classifier: Intended Audience :: Developers -Classifier: Programming Language :: Python :: 3 :: Only -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 :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Project-URL: Homepage, https://github.com/fastapi/annotated-doc -Project-URL: Documentation, https://github.com/fastapi/annotated-doc -Project-URL: Repository, https://github.com/fastapi/annotated-doc -Project-URL: Issues, https://github.com/fastapi/annotated-doc/issues -Project-URL: Changelog, https://github.com/fastapi/annotated-doc/release-notes.md -Requires-Python: >=3.8 -Description-Content-Type: text/markdown - -# Annotated Doc - -Document parameters, class attributes, return types, and variables inline, with `Annotated`. - - - Test - - - Coverage - - - Package version - - - Supported Python versions - - -## Installation - -```bash -pip install annotated-doc -``` - -Or with `uv`: - -```Python -uv add annotated-doc -``` - -## Usage - -Import `Doc` and pass a single literal string with the documentation for the specific parameter, class attribute, return type, or variable. - -For example, to document a parameter `name` in a function `hi` you could do: - -```Python -from typing import Annotated - -from annotated_doc import Doc - -def hi(name: Annotated[str, Doc("Who to say hi to")]) -> None: - print(f"Hi, {name}!") -``` - -You can also use it to document class attributes: - -```Python -from typing import Annotated - -from annotated_doc import Doc - -class User: - name: Annotated[str, Doc("The user's name")] - age: Annotated[int, Doc("The user's age")] -``` - -The same way, you could document return types and variables, or anything that could have a type annotation with `Annotated`. - -## Who Uses This - -`annotated-doc` was made for: - -* [FastAPI](https://fastapi.tiangolo.com/) -* [Typer](https://typer.tiangolo.com/) -* [SQLModel](https://sqlmodel.tiangolo.com/) -* [Asyncer](https://asyncer.tiangolo.com/) - -`annotated-doc` is supported by [griffe-typingdoc](https://github.com/mkdocstrings/griffe-typingdoc), which powers reference documentation like the one in the [FastAPI Reference](https://fastapi.tiangolo.com/reference/). - -## Reasons not to use `annotated-doc` - -You are already comfortable with one of the existing docstring formats, like: - -* Sphinx -* numpydoc -* Google -* Keras - -Your team is already comfortable using them. - -You prefer having the documentation about parameters all together in a docstring, separated from the code defining them. - -You care about a specific set of users, using one specific editor, and that editor already has support for the specific docstring format you use. - -## Reasons to use `annotated-doc` - -* No micro-syntax to learn for newcomers, it’s **just Python** syntax. -* **Editing** would be already fully supported by default by any editor (current or future) supporting Python syntax, including syntax errors, syntax highlighting, etc. -* **Rendering** would be relatively straightforward to implement by static tools (tools that don't need runtime execution), as the information can be extracted from the AST they normally already create. -* **Deduplication of information**: the name of a parameter would be defined in a single place, not duplicated inside of a docstring. -* **Elimination** of the possibility of having **inconsistencies** when removing a parameter or class variable and **forgetting to remove** its documentation. -* **Minimization** of the probability of adding a new parameter or class variable and **forgetting to add its documentation**. -* **Elimination** of the possibility of having **inconsistencies** between the **name** of a parameter in the **signature** and the name in the docstring when it is renamed. -* **Access** to the documentation string for each symbol at **runtime**, including existing (older) Python versions. -* A more formalized way to document other symbols, like type aliases, that could use Annotated. -* **Support** for apps using FastAPI, Typer and others. -* **AI Accessibility**: AI tools will have an easier way understanding each parameter as the distance from documentation to parameter is much closer. - -## History - -I ([@tiangolo](https://github.com/tiangolo)) originally wanted for this to be part of the Python standard library (in [PEP 727](https://peps.python.org/pep-0727/)), but the proposal was withdrawn as there was a fair amount of negative feedback and opposition. - -The conclusion was that this was better done as an external effort, in a third-party library. - -So, here it is, with a simpler approach, as a third-party library, in a way that can be used by others, starting with FastAPI and friends. - -## License - -This project is licensed under the terms of the MIT license. diff --git a/server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/RECORD b/server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/RECORD deleted file mode 100644 index e040ae2..0000000 --- a/server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/RECORD +++ /dev/null @@ -1,11 +0,0 @@ -annotated_doc-0.0.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -annotated_doc-0.0.4.dist-info/METADATA,sha256=Irm5KJua33dY2qKKAjJ-OhKaVBVIfwFGej_dSe3Z1TU,6566 -annotated_doc-0.0.4.dist-info/RECORD,, -annotated_doc-0.0.4.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90 -annotated_doc-0.0.4.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34 -annotated_doc-0.0.4.dist-info/licenses/LICENSE,sha256=__Fwd5pqy_ZavbQFwIfxzuF4ZpHkqWpANFF-SlBKDN8,1086 -annotated_doc/__init__.py,sha256=VuyxxUe80kfEyWnOrCx_Bk8hybo3aKo6RYBlkBBYW8k,52 -annotated_doc/__pycache__/__init__.cpython-313.pyc,, -annotated_doc/__pycache__/main.cpython-313.pyc,, -annotated_doc/main.py,sha256=5Zfvxv80SwwLqpRW73AZyZyiM4bWma9QWRbp_cgD20s,1075 -annotated_doc/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/WHEEL b/server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/WHEEL deleted file mode 100644 index 045c8ac..0000000 --- a/server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: pdm-backend (2.4.5) -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/entry_points.txt b/server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/entry_points.txt deleted file mode 100644 index c3ad472..0000000 --- a/server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/entry_points.txt +++ /dev/null @@ -1,4 +0,0 @@ -[console_scripts] - -[gui_scripts] - diff --git a/server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/licenses/LICENSE b/server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/licenses/LICENSE deleted file mode 100644 index 7a25446..0000000 --- a/server/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/licenses/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2025 Sebastián Ramírez - -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/server/venv/Lib/site-packages/annotated_doc/__init__.py b/server/venv/Lib/site-packages/annotated_doc/__init__.py deleted file mode 100644 index a0152a7..0000000 --- a/server/venv/Lib/site-packages/annotated_doc/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .main import Doc as Doc - -__version__ = "0.0.4" diff --git a/server/venv/Lib/site-packages/annotated_doc/main.py b/server/venv/Lib/site-packages/annotated_doc/main.py deleted file mode 100644 index 7063c59..0000000 --- a/server/venv/Lib/site-packages/annotated_doc/main.py +++ /dev/null @@ -1,36 +0,0 @@ -class Doc: - """Define the documentation of a type annotation using `Annotated`, to be - used in class attributes, function and method parameters, return values, - and variables. - - The value should be a positional-only string literal to allow static tools - like editors and documentation generators to use it. - - This complements docstrings. - - The string value passed is available in the attribute `documentation`. - - Example: - - ```Python - from typing import Annotated - from annotated_doc import Doc - - def hi(name: Annotated[str, Doc("Who to say hi to")]) -> None: - print(f"Hi, {name}!") - ``` - """ - - def __init__(self, documentation: str, /) -> None: - self.documentation = documentation - - def __repr__(self) -> str: - return f"Doc({self.documentation!r})" - - def __hash__(self) -> int: - return hash(self.documentation) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Doc): - return NotImplemented - return self.documentation == other.documentation diff --git a/server/venv/Lib/site-packages/annotated_doc/py.typed b/server/venv/Lib/site-packages/annotated_doc/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/INSTALLER b/server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/METADATA b/server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/METADATA deleted file mode 100644 index 3ac05cf..0000000 --- a/server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/METADATA +++ /dev/null @@ -1,295 +0,0 @@ -Metadata-Version: 2.3 -Name: annotated-types -Version: 0.7.0 -Summary: Reusable constraint types to use with typing.Annotated -Project-URL: Homepage, https://github.com/annotated-types/annotated-types -Project-URL: Source, https://github.com/annotated-types/annotated-types -Project-URL: Changelog, https://github.com/annotated-types/annotated-types/releases -Author-email: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com>, Samuel Colvin , Zac Hatfield-Dodds -License-File: LICENSE -Classifier: Development Status :: 4 - Beta -Classifier: Environment :: Console -Classifier: Environment :: MacOS X -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: Information Technology -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: POSIX :: Linux -Classifier: Operating System :: Unix -Classifier: Programming Language :: Python :: 3 :: Only -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 :: 3.12 -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Typing :: Typed -Requires-Python: >=3.8 -Requires-Dist: typing-extensions>=4.0.0; python_version < '3.9' -Description-Content-Type: text/markdown - -# annotated-types - -[![CI](https://github.com/annotated-types/annotated-types/workflows/CI/badge.svg?event=push)](https://github.com/annotated-types/annotated-types/actions?query=event%3Apush+branch%3Amain+workflow%3ACI) -[![pypi](https://img.shields.io/pypi/v/annotated-types.svg)](https://pypi.python.org/pypi/annotated-types) -[![versions](https://img.shields.io/pypi/pyversions/annotated-types.svg)](https://github.com/annotated-types/annotated-types) -[![license](https://img.shields.io/github/license/annotated-types/annotated-types.svg)](https://github.com/annotated-types/annotated-types/blob/main/LICENSE) - -[PEP-593](https://peps.python.org/pep-0593/) added `typing.Annotated` as a way of -adding context-specific metadata to existing types, and specifies that -`Annotated[T, x]` _should_ be treated as `T` by any tool or library without special -logic for `x`. - -This package provides metadata objects which can be used to represent common -constraints such as upper and lower bounds on scalar values and collection sizes, -a `Predicate` marker for runtime checks, and -descriptions of how we intend these metadata to be interpreted. In some cases, -we also note alternative representations which do not require this package. - -## Install - -```bash -pip install annotated-types -``` - -## Examples - -```python -from typing import Annotated -from annotated_types import Gt, Len, Predicate - -class MyClass: - age: Annotated[int, Gt(18)] # Valid: 19, 20, ... - # Invalid: 17, 18, "19", 19.0, ... - factors: list[Annotated[int, Predicate(is_prime)]] # Valid: 2, 3, 5, 7, 11, ... - # Invalid: 4, 8, -2, 5.0, "prime", ... - - my_list: Annotated[list[int], Len(0, 10)] # Valid: [], [10, 20, 30, 40, 50] - # Invalid: (1, 2), ["abc"], [0] * 20 -``` - -## Documentation - -_While `annotated-types` avoids runtime checks for performance, users should not -construct invalid combinations such as `MultipleOf("non-numeric")` or `Annotated[int, Len(3)]`. -Downstream implementors may choose to raise an error, emit a warning, silently ignore -a metadata item, etc., if the metadata objects described below are used with an -incompatible type - or for any other reason!_ - -### Gt, Ge, Lt, Le - -Express inclusive and/or exclusive bounds on orderable values - which may be numbers, -dates, times, strings, sets, etc. Note that the boundary value need not be of the -same type that was annotated, so long as they can be compared: `Annotated[int, Gt(1.5)]` -is fine, for example, and implies that the value is an integer x such that `x > 1.5`. - -We suggest that implementors may also interpret `functools.partial(operator.le, 1.5)` -as being equivalent to `Gt(1.5)`, for users who wish to avoid a runtime dependency on -the `annotated-types` package. - -To be explicit, these types have the following meanings: - -* `Gt(x)` - value must be "Greater Than" `x` - equivalent to exclusive minimum -* `Ge(x)` - value must be "Greater than or Equal" to `x` - equivalent to inclusive minimum -* `Lt(x)` - value must be "Less Than" `x` - equivalent to exclusive maximum -* `Le(x)` - value must be "Less than or Equal" to `x` - equivalent to inclusive maximum - -### Interval - -`Interval(gt, ge, lt, le)` allows you to specify an upper and lower bound with a single -metadata object. `None` attributes should be ignored, and non-`None` attributes -treated as per the single bounds above. - -### MultipleOf - -`MultipleOf(multiple_of=x)` might be interpreted in two ways: - -1. Python semantics, implying `value % multiple_of == 0`, or -2. [JSONschema semantics](https://json-schema.org/draft/2020-12/json-schema-validation.html#rfc.section.6.2.1), - where `int(value / multiple_of) == value / multiple_of`. - -We encourage users to be aware of these two common interpretations and their -distinct behaviours, especially since very large or non-integer numbers make -it easy to cause silent data corruption due to floating-point imprecision. - -We encourage libraries to carefully document which interpretation they implement. - -### MinLen, MaxLen, Len - -`Len()` implies that `min_length <= len(value) <= max_length` - lower and upper bounds are inclusive. - -As well as `Len()` which can optionally include upper and lower bounds, we also -provide `MinLen(x)` and `MaxLen(y)` which are equivalent to `Len(min_length=x)` -and `Len(max_length=y)` respectively. - -`Len`, `MinLen`, and `MaxLen` may be used with any type which supports `len(value)`. - -Examples of usage: - -* `Annotated[list, MaxLen(10)]` (or `Annotated[list, Len(max_length=10))`) - list must have a length of 10 or less -* `Annotated[str, MaxLen(10)]` - string must have a length of 10 or less -* `Annotated[list, MinLen(3))` (or `Annotated[list, Len(min_length=3))`) - list must have a length of 3 or more -* `Annotated[list, Len(4, 6)]` - list must have a length of 4, 5, or 6 -* `Annotated[list, Len(8, 8)]` - list must have a length of exactly 8 - -#### Changed in v0.4.0 - -* `min_inclusive` has been renamed to `min_length`, no change in meaning -* `max_exclusive` has been renamed to `max_length`, upper bound is now **inclusive** instead of **exclusive** -* The recommendation that slices are interpreted as `Len` has been removed due to ambiguity and different semantic - meaning of the upper bound in slices vs. `Len` - -See [issue #23](https://github.com/annotated-types/annotated-types/issues/23) for discussion. - -### Timezone - -`Timezone` can be used with a `datetime` or a `time` to express which timezones -are allowed. `Annotated[datetime, Timezone(None)]` must be a naive datetime. -`Timezone[...]` ([literal ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis)) -expresses that any timezone-aware datetime is allowed. You may also pass a specific -timezone string or [`tzinfo`](https://docs.python.org/3/library/datetime.html#tzinfo-objects) -object such as `Timezone(timezone.utc)` or `Timezone("Africa/Abidjan")` to express that you only -allow a specific timezone, though we note that this is often a symptom of fragile design. - -#### Changed in v0.x.x - -* `Timezone` accepts [`tzinfo`](https://docs.python.org/3/library/datetime.html#tzinfo-objects) objects instead of - `timezone`, extending compatibility to [`zoneinfo`](https://docs.python.org/3/library/zoneinfo.html) and third party libraries. - -### Unit - -`Unit(unit: str)` expresses that the annotated numeric value is the magnitude of -a quantity with the specified unit. For example, `Annotated[float, Unit("m/s")]` -would be a float representing a velocity in meters per second. - -Please note that `annotated_types` itself makes no attempt to parse or validate -the unit string in any way. That is left entirely to downstream libraries, -such as [`pint`](https://pint.readthedocs.io) or -[`astropy.units`](https://docs.astropy.org/en/stable/units/). - -An example of how a library might use this metadata: - -```python -from annotated_types import Unit -from typing import Annotated, TypeVar, Callable, Any, get_origin, get_args - -# given a type annotated with a unit: -Meters = Annotated[float, Unit("m")] - - -# you can cast the annotation to a specific unit type with any -# callable that accepts a string and returns the desired type -T = TypeVar("T") -def cast_unit(tp: Any, unit_cls: Callable[[str], T]) -> T | None: - if get_origin(tp) is Annotated: - for arg in get_args(tp): - if isinstance(arg, Unit): - return unit_cls(arg.unit) - return None - - -# using `pint` -import pint -pint_unit = cast_unit(Meters, pint.Unit) - - -# using `astropy.units` -import astropy.units as u -astropy_unit = cast_unit(Meters, u.Unit) -``` - -### Predicate - -`Predicate(func: Callable)` expresses that `func(value)` is truthy for valid values. -Users should prefer the statically inspectable metadata above, but if you need -the full power and flexibility of arbitrary runtime predicates... here it is. - -For some common constraints, we provide generic types: - -* `IsLower = Annotated[T, Predicate(str.islower)]` -* `IsUpper = Annotated[T, Predicate(str.isupper)]` -* `IsDigit = Annotated[T, Predicate(str.isdigit)]` -* `IsFinite = Annotated[T, Predicate(math.isfinite)]` -* `IsNotFinite = Annotated[T, Predicate(Not(math.isfinite))]` -* `IsNan = Annotated[T, Predicate(math.isnan)]` -* `IsNotNan = Annotated[T, Predicate(Not(math.isnan))]` -* `IsInfinite = Annotated[T, Predicate(math.isinf)]` -* `IsNotInfinite = Annotated[T, Predicate(Not(math.isinf))]` - -so that you can write e.g. `x: IsFinite[float] = 2.0` instead of the longer -(but exactly equivalent) `x: Annotated[float, Predicate(math.isfinite)] = 2.0`. - -Some libraries might have special logic to handle known or understandable predicates, -for example by checking for `str.isdigit` and using its presence to both call custom -logic to enforce digit-only strings, and customise some generated external schema. -Users are therefore encouraged to avoid indirection like `lambda s: s.lower()`, in -favor of introspectable methods such as `str.lower` or `re.compile("pattern").search`. - -To enable basic negation of commonly used predicates like `math.isnan` without introducing introspection that makes it impossible for implementers to introspect the predicate we provide a `Not` wrapper that simply negates the predicate in an introspectable manner. Several of the predicates listed above are created in this manner. - -We do not specify what behaviour should be expected for predicates that raise -an exception. For example `Annotated[int, Predicate(str.isdigit)]` might silently -skip invalid constraints, or statically raise an error; or it might try calling it -and then propagate or discard the resulting -`TypeError: descriptor 'isdigit' for 'str' objects doesn't apply to a 'int' object` -exception. We encourage libraries to document the behaviour they choose. - -### Doc - -`doc()` can be used to add documentation information in `Annotated`, for function and method parameters, variables, class attributes, return types, and any place where `Annotated` can be used. - -It expects a value that can be statically analyzed, as the main use case is for static analysis, editors, documentation generators, and similar tools. - -It returns a `DocInfo` class with a single attribute `documentation` containing the value passed to `doc()`. - -This is the early adopter's alternative form of the [`typing-doc` proposal](https://github.com/tiangolo/fastapi/blob/typing-doc/typing_doc.md). - -### Integrating downstream types with `GroupedMetadata` - -Implementers may choose to provide a convenience wrapper that groups multiple pieces of metadata. -This can help reduce verbosity and cognitive overhead for users. -For example, an implementer like Pydantic might provide a `Field` or `Meta` type that accepts keyword arguments and transforms these into low-level metadata: - -```python -from dataclasses import dataclass -from typing import Iterator -from annotated_types import GroupedMetadata, Ge - -@dataclass -class Field(GroupedMetadata): - ge: int | None = None - description: str | None = None - - def __iter__(self) -> Iterator[object]: - # Iterating over a GroupedMetadata object should yield annotated-types - # constraint metadata objects which describe it as fully as possible, - # and may include other unknown objects too. - if self.ge is not None: - yield Ge(self.ge) - if self.description is not None: - yield Description(self.description) -``` - -Libraries consuming annotated-types constraints should check for `GroupedMetadata` and unpack it by iterating over the object and treating the results as if they had been "unpacked" in the `Annotated` type. The same logic should be applied to the [PEP 646 `Unpack` type](https://peps.python.org/pep-0646/), so that `Annotated[T, Field(...)]`, `Annotated[T, Unpack[Field(...)]]` and `Annotated[T, *Field(...)]` are all treated consistently. - -Libraries consuming annotated-types should also ignore any metadata they do not recongize that came from unpacking a `GroupedMetadata`, just like they ignore unrecognized metadata in `Annotated` itself. - -Our own `annotated_types.Interval` class is a `GroupedMetadata` which unpacks itself into `Gt`, `Lt`, etc., so this is not an abstract concern. Similarly, `annotated_types.Len` is a `GroupedMetadata` which unpacks itself into `MinLen` (optionally) and `MaxLen`. - -### Consuming metadata - -We intend to not be prescriptive as to _how_ the metadata and constraints are used, but as an example of how one might parse constraints from types annotations see our [implementation in `test_main.py`](https://github.com/annotated-types/annotated-types/blob/f59cf6d1b5255a0fe359b93896759a180bec30ae/tests/test_main.py#L94-L103). - -It is up to the implementer to determine how this metadata is used. -You could use the metadata for runtime type checking, for generating schemas or to generate example data, amongst other use cases. - -## Design & History - -This package was designed at the PyCon 2022 sprints by the maintainers of Pydantic -and Hypothesis, with the goal of making it as easy as possible for end-users to -provide more informative annotations for use by runtime libraries. - -It is deliberately minimal, and following PEP-593 allows considerable downstream -discretion in what (if anything!) they choose to support. Nonetheless, we expect -that staying simple and covering _only_ the most common use-cases will give users -and maintainers the best experience we can. If you'd like more constraints for your -types - follow our lead, by defining them and documenting them downstream! diff --git a/server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/RECORD b/server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/RECORD deleted file mode 100644 index 01b9e66..0000000 --- a/server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/RECORD +++ /dev/null @@ -1,10 +0,0 @@ -annotated_types-0.7.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -annotated_types-0.7.0.dist-info/METADATA,sha256=7ltqxksJJ0wCYFGBNIQCWTlWQGeAH0hRFdnK3CB895E,15046 -annotated_types-0.7.0.dist-info/RECORD,, -annotated_types-0.7.0.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87 -annotated_types-0.7.0.dist-info/licenses/LICENSE,sha256=_hBJiEsaDZNCkB6I4H8ykl0ksxIdmXK2poBfuYJLCV0,1083 -annotated_types/__init__.py,sha256=RynLsRKUEGI0KimXydlD1fZEfEzWwDo0Uon3zOKhG1Q,13819 -annotated_types/__pycache__/__init__.cpython-313.pyc,, -annotated_types/__pycache__/test_cases.cpython-313.pyc,, -annotated_types/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -annotated_types/test_cases.py,sha256=zHFX6EpcMbGJ8FzBYDbO56bPwx_DYIVSKbZM-4B3_lg,6421 diff --git a/server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/WHEEL b/server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/WHEEL deleted file mode 100644 index 516596c..0000000 --- a/server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.24.2 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/licenses/LICENSE b/server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/licenses/LICENSE deleted file mode 100644 index d99323a..0000000 --- a/server/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2022 the 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/server/venv/Lib/site-packages/annotated_types/__init__.py b/server/venv/Lib/site-packages/annotated_types/__init__.py deleted file mode 100644 index 74e0dee..0000000 --- a/server/venv/Lib/site-packages/annotated_types/__init__.py +++ /dev/null @@ -1,432 +0,0 @@ -import math -import sys -import types -from dataclasses import dataclass -from datetime import tzinfo -from typing import TYPE_CHECKING, Any, Callable, Iterator, Optional, SupportsFloat, SupportsIndex, TypeVar, Union - -if sys.version_info < (3, 8): - from typing_extensions import Protocol, runtime_checkable -else: - from typing import Protocol, runtime_checkable - -if sys.version_info < (3, 9): - from typing_extensions import Annotated, Literal -else: - from typing import Annotated, Literal - -if sys.version_info < (3, 10): - EllipsisType = type(Ellipsis) - KW_ONLY = {} - SLOTS = {} -else: - from types import EllipsisType - - KW_ONLY = {"kw_only": True} - SLOTS = {"slots": True} - - -__all__ = ( - 'BaseMetadata', - 'GroupedMetadata', - 'Gt', - 'Ge', - 'Lt', - 'Le', - 'Interval', - 'MultipleOf', - 'MinLen', - 'MaxLen', - 'Len', - 'Timezone', - 'Predicate', - 'LowerCase', - 'UpperCase', - 'IsDigits', - 'IsFinite', - 'IsNotFinite', - 'IsNan', - 'IsNotNan', - 'IsInfinite', - 'IsNotInfinite', - 'doc', - 'DocInfo', - '__version__', -) - -__version__ = '0.7.0' - - -T = TypeVar('T') - - -# arguments that start with __ are considered -# positional only -# see https://peps.python.org/pep-0484/#positional-only-arguments - - -class SupportsGt(Protocol): - def __gt__(self: T, __other: T) -> bool: - ... - - -class SupportsGe(Protocol): - def __ge__(self: T, __other: T) -> bool: - ... - - -class SupportsLt(Protocol): - def __lt__(self: T, __other: T) -> bool: - ... - - -class SupportsLe(Protocol): - def __le__(self: T, __other: T) -> bool: - ... - - -class SupportsMod(Protocol): - def __mod__(self: T, __other: T) -> T: - ... - - -class SupportsDiv(Protocol): - def __div__(self: T, __other: T) -> T: - ... - - -class BaseMetadata: - """Base class for all metadata. - - This exists mainly so that implementers - can do `isinstance(..., BaseMetadata)` while traversing field annotations. - """ - - __slots__ = () - - -@dataclass(frozen=True, **SLOTS) -class Gt(BaseMetadata): - """Gt(gt=x) implies that the value must be greater than x. - - It can be used with any type that supports the ``>`` operator, - including numbers, dates and times, strings, sets, and so on. - """ - - gt: SupportsGt - - -@dataclass(frozen=True, **SLOTS) -class Ge(BaseMetadata): - """Ge(ge=x) implies that the value must be greater than or equal to x. - - It can be used with any type that supports the ``>=`` operator, - including numbers, dates and times, strings, sets, and so on. - """ - - ge: SupportsGe - - -@dataclass(frozen=True, **SLOTS) -class Lt(BaseMetadata): - """Lt(lt=x) implies that the value must be less than x. - - It can be used with any type that supports the ``<`` operator, - including numbers, dates and times, strings, sets, and so on. - """ - - lt: SupportsLt - - -@dataclass(frozen=True, **SLOTS) -class Le(BaseMetadata): - """Le(le=x) implies that the value must be less than or equal to x. - - It can be used with any type that supports the ``<=`` operator, - including numbers, dates and times, strings, sets, and so on. - """ - - le: SupportsLe - - -@runtime_checkable -class GroupedMetadata(Protocol): - """A grouping of multiple objects, like typing.Unpack. - - `GroupedMetadata` on its own is not metadata and has no meaning. - All of the constraints and metadata should be fully expressable - in terms of the `BaseMetadata`'s returned by `GroupedMetadata.__iter__()`. - - Concrete implementations should override `GroupedMetadata.__iter__()` - to add their own metadata. - For example: - - >>> @dataclass - >>> class Field(GroupedMetadata): - >>> gt: float | None = None - >>> description: str | None = None - ... - >>> def __iter__(self) -> Iterable[object]: - >>> if self.gt is not None: - >>> yield Gt(self.gt) - >>> if self.description is not None: - >>> yield Description(self.gt) - - Also see the implementation of `Interval` below for an example. - - Parsers should recognize this and unpack it so that it can be used - both with and without unpacking: - - - `Annotated[int, Field(...)]` (parser must unpack Field) - - `Annotated[int, *Field(...)]` (PEP-646) - """ # noqa: trailing-whitespace - - @property - def __is_annotated_types_grouped_metadata__(self) -> Literal[True]: - return True - - def __iter__(self) -> Iterator[object]: - ... - - if not TYPE_CHECKING: - __slots__ = () # allow subclasses to use slots - - def __init_subclass__(cls, *args: Any, **kwargs: Any) -> None: - # Basic ABC like functionality without the complexity of an ABC - super().__init_subclass__(*args, **kwargs) - if cls.__iter__ is GroupedMetadata.__iter__: - raise TypeError("Can't subclass GroupedMetadata without implementing __iter__") - - def __iter__(self) -> Iterator[object]: # noqa: F811 - raise NotImplementedError # more helpful than "None has no attribute..." type errors - - -@dataclass(frozen=True, **KW_ONLY, **SLOTS) -class Interval(GroupedMetadata): - """Interval can express inclusive or exclusive bounds with a single object. - - It accepts keyword arguments ``gt``, ``ge``, ``lt``, and/or ``le``, which - are interpreted the same way as the single-bound constraints. - """ - - gt: Union[SupportsGt, None] = None - ge: Union[SupportsGe, None] = None - lt: Union[SupportsLt, None] = None - le: Union[SupportsLe, None] = None - - def __iter__(self) -> Iterator[BaseMetadata]: - """Unpack an Interval into zero or more single-bounds.""" - if self.gt is not None: - yield Gt(self.gt) - if self.ge is not None: - yield Ge(self.ge) - if self.lt is not None: - yield Lt(self.lt) - if self.le is not None: - yield Le(self.le) - - -@dataclass(frozen=True, **SLOTS) -class MultipleOf(BaseMetadata): - """MultipleOf(multiple_of=x) might be interpreted in two ways: - - 1. Python semantics, implying ``value % multiple_of == 0``, or - 2. JSONschema semantics, where ``int(value / multiple_of) == value / multiple_of`` - - We encourage users to be aware of these two common interpretations, - and libraries to carefully document which they implement. - """ - - multiple_of: Union[SupportsDiv, SupportsMod] - - -@dataclass(frozen=True, **SLOTS) -class MinLen(BaseMetadata): - """ - MinLen() implies minimum inclusive length, - e.g. ``len(value) >= min_length``. - """ - - min_length: Annotated[int, Ge(0)] - - -@dataclass(frozen=True, **SLOTS) -class MaxLen(BaseMetadata): - """ - MaxLen() implies maximum inclusive length, - e.g. ``len(value) <= max_length``. - """ - - max_length: Annotated[int, Ge(0)] - - -@dataclass(frozen=True, **SLOTS) -class Len(GroupedMetadata): - """ - Len() implies that ``min_length <= len(value) <= max_length``. - - Upper bound may be omitted or ``None`` to indicate no upper length bound. - """ - - min_length: Annotated[int, Ge(0)] = 0 - max_length: Optional[Annotated[int, Ge(0)]] = None - - def __iter__(self) -> Iterator[BaseMetadata]: - """Unpack a Len into zone or more single-bounds.""" - if self.min_length > 0: - yield MinLen(self.min_length) - if self.max_length is not None: - yield MaxLen(self.max_length) - - -@dataclass(frozen=True, **SLOTS) -class Timezone(BaseMetadata): - """Timezone(tz=...) requires a datetime to be aware (or ``tz=None``, naive). - - ``Annotated[datetime, Timezone(None)]`` must be a naive datetime. - ``Timezone[...]`` (the ellipsis literal) expresses that the datetime must be - tz-aware but any timezone is allowed. - - You may also pass a specific timezone string or tzinfo object such as - ``Timezone(timezone.utc)`` or ``Timezone("Africa/Abidjan")`` to express that - you only allow a specific timezone, though we note that this is often - a symptom of poor design. - """ - - tz: Union[str, tzinfo, EllipsisType, None] - - -@dataclass(frozen=True, **SLOTS) -class Unit(BaseMetadata): - """Indicates that the value is a physical quantity with the specified unit. - - It is intended for usage with numeric types, where the value represents the - magnitude of the quantity. For example, ``distance: Annotated[float, Unit('m')]`` - or ``speed: Annotated[float, Unit('m/s')]``. - - Interpretation of the unit string is left to the discretion of the consumer. - It is suggested to follow conventions established by python libraries that work - with physical quantities, such as - - - ``pint`` : - - ``astropy.units``: - - For indicating a quantity with a certain dimensionality but without a specific unit - it is recommended to use square brackets, e.g. `Annotated[float, Unit('[time]')]`. - Note, however, ``annotated_types`` itself makes no use of the unit string. - """ - - unit: str - - -@dataclass(frozen=True, **SLOTS) -class Predicate(BaseMetadata): - """``Predicate(func: Callable)`` implies `func(value)` is truthy for valid values. - - Users should prefer statically inspectable metadata, but if you need the full - power and flexibility of arbitrary runtime predicates... here it is. - - We provide a few predefined predicates for common string constraints: - ``IsLower = Predicate(str.islower)``, ``IsUpper = Predicate(str.isupper)``, and - ``IsDigits = Predicate(str.isdigit)``. Users are encouraged to use methods which - can be given special handling, and avoid indirection like ``lambda s: s.lower()``. - - Some libraries might have special logic to handle certain predicates, e.g. by - checking for `str.isdigit` and using its presence to both call custom logic to - enforce digit-only strings, and customise some generated external schema. - - We do not specify what behaviour should be expected for predicates that raise - an exception. For example `Annotated[int, Predicate(str.isdigit)]` might silently - skip invalid constraints, or statically raise an error; or it might try calling it - and then propagate or discard the resulting exception. - """ - - func: Callable[[Any], bool] - - def __repr__(self) -> str: - if getattr(self.func, "__name__", "") == "": - return f"{self.__class__.__name__}({self.func!r})" - if isinstance(self.func, (types.MethodType, types.BuiltinMethodType)) and ( - namespace := getattr(self.func.__self__, "__name__", None) - ): - return f"{self.__class__.__name__}({namespace}.{self.func.__name__})" - if isinstance(self.func, type(str.isascii)): # method descriptor - return f"{self.__class__.__name__}({self.func.__qualname__})" - return f"{self.__class__.__name__}({self.func.__name__})" - - -@dataclass -class Not: - func: Callable[[Any], bool] - - def __call__(self, __v: Any) -> bool: - return not self.func(__v) - - -_StrType = TypeVar("_StrType", bound=str) - -LowerCase = Annotated[_StrType, Predicate(str.islower)] -""" -Return True if the string is a lowercase string, False otherwise. - -A string is lowercase if all cased characters in the string are lowercase and there is at least one cased character in the string. -""" # noqa: E501 -UpperCase = Annotated[_StrType, Predicate(str.isupper)] -""" -Return True if the string is an uppercase string, False otherwise. - -A string is uppercase if all cased characters in the string are uppercase and there is at least one cased character in the string. -""" # noqa: E501 -IsDigit = Annotated[_StrType, Predicate(str.isdigit)] -IsDigits = IsDigit # type: ignore # plural for backwards compatibility, see #63 -""" -Return True if the string is a digit string, False otherwise. - -A string is a digit string if all characters in the string are digits and there is at least one character in the string. -""" # noqa: E501 -IsAscii = Annotated[_StrType, Predicate(str.isascii)] -""" -Return True if all characters in the string are ASCII, False otherwise. - -ASCII characters have code points in the range U+0000-U+007F. Empty string is ASCII too. -""" - -_NumericType = TypeVar('_NumericType', bound=Union[SupportsFloat, SupportsIndex]) -IsFinite = Annotated[_NumericType, Predicate(math.isfinite)] -"""Return True if x is neither an infinity nor a NaN, and False otherwise.""" -IsNotFinite = Annotated[_NumericType, Predicate(Not(math.isfinite))] -"""Return True if x is one of infinity or NaN, and False otherwise""" -IsNan = Annotated[_NumericType, Predicate(math.isnan)] -"""Return True if x is a NaN (not a number), and False otherwise.""" -IsNotNan = Annotated[_NumericType, Predicate(Not(math.isnan))] -"""Return True if x is anything but NaN (not a number), and False otherwise.""" -IsInfinite = Annotated[_NumericType, Predicate(math.isinf)] -"""Return True if x is a positive or negative infinity, and False otherwise.""" -IsNotInfinite = Annotated[_NumericType, Predicate(Not(math.isinf))] -"""Return True if x is neither a positive or negative infinity, and False otherwise.""" - -try: - from typing_extensions import DocInfo, doc # type: ignore [attr-defined] -except ImportError: - - @dataclass(frozen=True, **SLOTS) - class DocInfo: # type: ignore [no-redef] - """ " - The return value of doc(), mainly to be used by tools that want to extract the - Annotated documentation at runtime. - """ - - documentation: str - """The documentation string passed to doc().""" - - def doc( - documentation: str, - ) -> DocInfo: - """ - Add documentation to a type annotation inside of Annotated. - - For example: - - >>> def hi(name: Annotated[int, doc("The name of the user")]) -> None: ... - """ - return DocInfo(documentation) diff --git a/server/venv/Lib/site-packages/annotated_types/py.typed b/server/venv/Lib/site-packages/annotated_types/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/server/venv/Lib/site-packages/annotated_types/test_cases.py b/server/venv/Lib/site-packages/annotated_types/test_cases.py deleted file mode 100644 index d9164d6..0000000 --- a/server/venv/Lib/site-packages/annotated_types/test_cases.py +++ /dev/null @@ -1,151 +0,0 @@ -import math -import sys -from datetime import date, datetime, timedelta, timezone -from decimal import Decimal -from typing import Any, Dict, Iterable, Iterator, List, NamedTuple, Set, Tuple - -if sys.version_info < (3, 9): - from typing_extensions import Annotated -else: - from typing import Annotated - -import annotated_types as at - - -class Case(NamedTuple): - """ - A test case for `annotated_types`. - """ - - annotation: Any - valid_cases: Iterable[Any] - invalid_cases: Iterable[Any] - - -def cases() -> Iterable[Case]: - # Gt, Ge, Lt, Le - yield Case(Annotated[int, at.Gt(4)], (5, 6, 1000), (4, 0, -1)) - yield Case(Annotated[float, at.Gt(0.5)], (0.6, 0.7, 0.8, 0.9), (0.5, 0.0, -0.1)) - yield Case( - Annotated[datetime, at.Gt(datetime(2000, 1, 1))], - [datetime(2000, 1, 2), datetime(2000, 1, 3)], - [datetime(2000, 1, 1), datetime(1999, 12, 31)], - ) - yield Case( - Annotated[datetime, at.Gt(date(2000, 1, 1))], - [date(2000, 1, 2), date(2000, 1, 3)], - [date(2000, 1, 1), date(1999, 12, 31)], - ) - yield Case( - Annotated[datetime, at.Gt(Decimal('1.123'))], - [Decimal('1.1231'), Decimal('123')], - [Decimal('1.123'), Decimal('0')], - ) - - yield Case(Annotated[int, at.Ge(4)], (4, 5, 6, 1000, 4), (0, -1)) - yield Case(Annotated[float, at.Ge(0.5)], (0.5, 0.6, 0.7, 0.8, 0.9), (0.4, 0.0, -0.1)) - yield Case( - Annotated[datetime, at.Ge(datetime(2000, 1, 1))], - [datetime(2000, 1, 2), datetime(2000, 1, 3)], - [datetime(1998, 1, 1), datetime(1999, 12, 31)], - ) - - yield Case(Annotated[int, at.Lt(4)], (0, -1), (4, 5, 6, 1000, 4)) - yield Case(Annotated[float, at.Lt(0.5)], (0.4, 0.0, -0.1), (0.5, 0.6, 0.7, 0.8, 0.9)) - yield Case( - Annotated[datetime, at.Lt(datetime(2000, 1, 1))], - [datetime(1999, 12, 31), datetime(1999, 12, 31)], - [datetime(2000, 1, 2), datetime(2000, 1, 3)], - ) - - yield Case(Annotated[int, at.Le(4)], (4, 0, -1), (5, 6, 1000)) - yield Case(Annotated[float, at.Le(0.5)], (0.5, 0.0, -0.1), (0.6, 0.7, 0.8, 0.9)) - yield Case( - Annotated[datetime, at.Le(datetime(2000, 1, 1))], - [datetime(2000, 1, 1), datetime(1999, 12, 31)], - [datetime(2000, 1, 2), datetime(2000, 1, 3)], - ) - - # Interval - yield Case(Annotated[int, at.Interval(gt=4)], (5, 6, 1000), (4, 0, -1)) - yield Case(Annotated[int, at.Interval(gt=4, lt=10)], (5, 6), (4, 10, 1000, 0, -1)) - yield Case(Annotated[float, at.Interval(ge=0.5, le=1)], (0.5, 0.9, 1), (0.49, 1.1)) - yield Case( - Annotated[datetime, at.Interval(gt=datetime(2000, 1, 1), le=datetime(2000, 1, 3))], - [datetime(2000, 1, 2), datetime(2000, 1, 3)], - [datetime(2000, 1, 1), datetime(2000, 1, 4)], - ) - - yield Case(Annotated[int, at.MultipleOf(multiple_of=3)], (0, 3, 9), (1, 2, 4)) - yield Case(Annotated[float, at.MultipleOf(multiple_of=0.5)], (0, 0.5, 1, 1.5), (0.4, 1.1)) - - # lengths - - yield Case(Annotated[str, at.MinLen(3)], ('123', '1234', 'x' * 10), ('', '1', '12')) - yield Case(Annotated[str, at.Len(3)], ('123', '1234', 'x' * 10), ('', '1', '12')) - yield Case(Annotated[List[int], at.MinLen(3)], ([1, 2, 3], [1, 2, 3, 4], [1] * 10), ([], [1], [1, 2])) - yield Case(Annotated[List[int], at.Len(3)], ([1, 2, 3], [1, 2, 3, 4], [1] * 10), ([], [1], [1, 2])) - - yield Case(Annotated[str, at.MaxLen(4)], ('', '1234'), ('12345', 'x' * 10)) - yield Case(Annotated[str, at.Len(0, 4)], ('', '1234'), ('12345', 'x' * 10)) - yield Case(Annotated[List[str], at.MaxLen(4)], ([], ['a', 'bcdef'], ['a', 'b', 'c']), (['a'] * 5, ['b'] * 10)) - yield Case(Annotated[List[str], at.Len(0, 4)], ([], ['a', 'bcdef'], ['a', 'b', 'c']), (['a'] * 5, ['b'] * 10)) - - yield Case(Annotated[str, at.Len(3, 5)], ('123', '12345'), ('', '1', '12', '123456', 'x' * 10)) - yield Case(Annotated[str, at.Len(3, 3)], ('123',), ('12', '1234')) - - yield Case(Annotated[Dict[int, int], at.Len(2, 3)], [{1: 1, 2: 2}], [{}, {1: 1}, {1: 1, 2: 2, 3: 3, 4: 4}]) - yield Case(Annotated[Set[int], at.Len(2, 3)], ({1, 2}, {1, 2, 3}), (set(), {1}, {1, 2, 3, 4})) - yield Case(Annotated[Tuple[int, ...], at.Len(2, 3)], ((1, 2), (1, 2, 3)), ((), (1,), (1, 2, 3, 4))) - - # Timezone - - yield Case( - Annotated[datetime, at.Timezone(None)], [datetime(2000, 1, 1)], [datetime(2000, 1, 1, tzinfo=timezone.utc)] - ) - yield Case( - Annotated[datetime, at.Timezone(...)], [datetime(2000, 1, 1, tzinfo=timezone.utc)], [datetime(2000, 1, 1)] - ) - yield Case( - Annotated[datetime, at.Timezone(timezone.utc)], - [datetime(2000, 1, 1, tzinfo=timezone.utc)], - [datetime(2000, 1, 1), datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=6)))], - ) - yield Case( - Annotated[datetime, at.Timezone('Europe/London')], - [datetime(2000, 1, 1, tzinfo=timezone(timedelta(0), name='Europe/London'))], - [datetime(2000, 1, 1), datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=6)))], - ) - - # Quantity - - yield Case(Annotated[float, at.Unit(unit='m')], (5, 4.2), ('5m', '4.2m')) - - # predicate types - - yield Case(at.LowerCase[str], ['abc', 'foobar'], ['', 'A', 'Boom']) - yield Case(at.UpperCase[str], ['ABC', 'DEFO'], ['', 'a', 'abc', 'AbC']) - yield Case(at.IsDigit[str], ['123'], ['', 'ab', 'a1b2']) - yield Case(at.IsAscii[str], ['123', 'foo bar'], ['£100', '😊', 'whatever 👀']) - - yield Case(Annotated[int, at.Predicate(lambda x: x % 2 == 0)], [0, 2, 4], [1, 3, 5]) - - yield Case(at.IsFinite[float], [1.23], [math.nan, math.inf, -math.inf]) - yield Case(at.IsNotFinite[float], [math.nan, math.inf], [1.23]) - yield Case(at.IsNan[float], [math.nan], [1.23, math.inf]) - yield Case(at.IsNotNan[float], [1.23, math.inf], [math.nan]) - yield Case(at.IsInfinite[float], [math.inf], [math.nan, 1.23]) - yield Case(at.IsNotInfinite[float], [math.nan, 1.23], [math.inf]) - - # check stacked predicates - yield Case(at.IsInfinite[Annotated[float, at.Predicate(lambda x: x > 0)]], [math.inf], [-math.inf, 1.23, math.nan]) - - # doc - yield Case(Annotated[int, at.doc("A number")], [1, 2], []) - - # custom GroupedMetadata - class MyCustomGroupedMetadata(at.GroupedMetadata): - def __iter__(self) -> Iterator[at.Predicate]: - yield at.Predicate(lambda x: float(x).is_integer()) - - yield Case(Annotated[float, MyCustomGroupedMetadata()], [0, 2.0], [0.01, 1.5]) diff --git a/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/INSTALLER b/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/METADATA b/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/METADATA deleted file mode 100644 index 7840c30..0000000 --- a/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/METADATA +++ /dev/null @@ -1,107 +0,0 @@ -Metadata-Version: 2.4 -Name: anyio -Version: 4.14.0 -Summary: High-level concurrency and networking framework on top of asyncio or Trio -Author-email: Alex Grönholm -License-Expression: MIT -Project-URL: Documentation, https://anyio.readthedocs.io/en/latest/ -Project-URL: Changelog, https://anyio.readthedocs.io/en/stable/versionhistory.html -Project-URL: Source code, https://github.com/agronholm/anyio -Project-URL: Issue tracker, https://github.com/agronholm/anyio/issues -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Framework :: AnyIO -Classifier: Typing :: Typed -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: 3.15 -Requires-Python: >=3.10 -Description-Content-Type: text/x-rst -License-File: LICENSE -Requires-Dist: exceptiongroup>=1.0.2; python_version < "3.11" -Requires-Dist: idna>=2.8 -Requires-Dist: typing_extensions>=4.5; python_version < "3.13" -Provides-Extra: trio -Requires-Dist: trio>=0.32.0; extra == "trio" -Dynamic: license-file - -.. image:: https://github.com/agronholm/anyio/actions/workflows/test.yml/badge.svg - :target: https://github.com/agronholm/anyio/actions/workflows/test.yml - :alt: Build Status -.. image:: https://coveralls.io/repos/github/agronholm/anyio/badge.svg?branch=master - :target: https://coveralls.io/github/agronholm/anyio?branch=master - :alt: Code Coverage -.. image:: https://readthedocs.org/projects/anyio/badge/?version=latest - :target: https://anyio.readthedocs.io/en/latest/?badge=latest - :alt: Documentation -.. image:: https://badges.gitter.im/gitterHQ/gitter.svg - :target: https://gitter.im/python-trio/AnyIO - :alt: Gitter chat -.. image:: https://tidelift.com/badges/package/pypi/anyio - :target: https://tidelift.com/subscription/pkg/pypi-anyio - :alt: Tidelift - -AnyIO is an asynchronous networking and concurrency library that works on top of either asyncio_ or -Trio_. It implements Trio-like `structured concurrency`_ (SC) on top of asyncio and works in harmony -with the native SC of Trio itself. - -Applications and libraries written against AnyIO's API will run unmodified on either asyncio_ or -Trio_. AnyIO can also be adopted into a library or application incrementally – bit by bit, no full -refactoring necessary. It will blend in with the native libraries of your chosen backend. - -To find out why you might want to use AnyIO's APIs instead of asyncio's, you can read about it -`here `_. - -Documentation -------------- - -View full documentation at: https://anyio.readthedocs.io/ - -Features --------- - -AnyIO offers the following functionality: - -* Task groups (nurseries_ in trio terminology) -* High-level networking (TCP, UDP and UNIX sockets) - - * `Happy eyeballs`_ algorithm for TCP connections (more robust than that of asyncio on Python - 3.8) - * async/await style UDP sockets (unlike asyncio where you still have to use Transports and - Protocols) - -* A versatile API for byte streams and object streams -* Inter-task synchronization and communication (locks, conditions, events, semaphores, object - streams) -* Worker threads -* Subprocesses -* Subinterpreter support for code parallelization (on Python 3.13 and later) -* Asynchronous file I/O (using worker threads) -* Signal handling -* Asynchronous versions of the functools_ and itertools_ modules - -AnyIO also comes with its own pytest_ plugin which also supports asynchronous fixtures. -It even works with the popular Hypothesis_ library. - -.. _asyncio: https://docs.python.org/3/library/asyncio.html -.. _Trio: https://github.com/python-trio/trio -.. _structured concurrency: https://en.wikipedia.org/wiki/Structured_concurrency -.. _nurseries: https://trio.readthedocs.io/en/stable/reference-core.html#nurseries-and-spawning -.. _Happy eyeballs: https://en.wikipedia.org/wiki/Happy_Eyeballs -.. _pytest: https://docs.pytest.org/en/latest/ -.. _functools: https://docs.python.org/3/library/functools.html -.. _itertools: https://docs.python.org/3/library/itertools.html -.. _Hypothesis: https://hypothesis.works/ - -Security contact information ----------------------------- - -To report a security vulnerability, please use the `Tidelift security contact`_. -Tidelift will coordinate the fix and disclosure. - -.. _Tidelift security contact: https://tidelift.com/security diff --git a/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/RECORD b/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/RECORD deleted file mode 100644 index a691626..0000000 --- a/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/RECORD +++ /dev/null @@ -1,94 +0,0 @@ -anyio-4.14.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -anyio-4.14.0.dist-info/METADATA,sha256=ZozV8u8z7Ya7tmsk9Uetxz7-QFNpHH2nVBLy041h6xo,4645 -anyio-4.14.0.dist-info/RECORD,, -anyio-4.14.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91 -anyio-4.14.0.dist-info/entry_points.txt,sha256=_d6Yu6uiaZmNe0CydowirE9Cmg7zUL2g08tQpoS3Qvc,39 -anyio-4.14.0.dist-info/licenses/LICENSE,sha256=U2GsncWPLvX9LpsJxoKXwX8ElQkJu8gCO9uC6s8iwrA,1081 -anyio-4.14.0.dist-info/top_level.txt,sha256=QglSMiWX8_5dpoVAEIHdEYzvqFMdSYWmCj6tYw2ITkQ,6 -anyio/__init__.py,sha256=HitUIfzvAojSeaHVmJ9rFn8k_yI63G6s_jUL2QChf4U,6405 -anyio/__pycache__/__init__.cpython-313.pyc,, -anyio/__pycache__/from_thread.cpython-313.pyc,, -anyio/__pycache__/functools.cpython-313.pyc,, -anyio/__pycache__/itertools.cpython-313.pyc,, -anyio/__pycache__/lowlevel.cpython-313.pyc,, -anyio/__pycache__/pytest_plugin.cpython-313.pyc,, -anyio/__pycache__/to_interpreter.cpython-313.pyc,, -anyio/__pycache__/to_process.cpython-313.pyc,, -anyio/__pycache__/to_thread.cpython-313.pyc,, -anyio/_backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -anyio/_backends/__pycache__/__init__.cpython-313.pyc,, -anyio/_backends/__pycache__/_asyncio.cpython-313.pyc,, -anyio/_backends/__pycache__/_trio.cpython-313.pyc,, -anyio/_backends/_asyncio.py,sha256=kX_Zv3F_SnWqWqSLmfPsDFxvsJLaATSeivzg6Gho3Rs,101971 -anyio/_backends/_trio.py,sha256=vR0ZgxVnOo4AHhHcHVG0worMc-3ZNpAZ6Vxh0m0ZZC0,45189 -anyio/_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -anyio/_core/__pycache__/__init__.cpython-313.pyc,, -anyio/_core/__pycache__/_asyncio_selector_thread.cpython-313.pyc,, -anyio/_core/__pycache__/_contextmanagers.cpython-313.pyc,, -anyio/_core/__pycache__/_eventloop.cpython-313.pyc,, -anyio/_core/__pycache__/_exceptions.cpython-313.pyc,, -anyio/_core/__pycache__/_fileio.cpython-313.pyc,, -anyio/_core/__pycache__/_resources.cpython-313.pyc,, -anyio/_core/__pycache__/_signals.cpython-313.pyc,, -anyio/_core/__pycache__/_sockets.cpython-313.pyc,, -anyio/_core/__pycache__/_streams.cpython-313.pyc,, -anyio/_core/__pycache__/_subprocesses.cpython-313.pyc,, -anyio/_core/__pycache__/_synchronization.cpython-313.pyc,, -anyio/_core/__pycache__/_tasks.cpython-313.pyc,, -anyio/_core/__pycache__/_tempfile.cpython-313.pyc,, -anyio/_core/__pycache__/_testing.cpython-313.pyc,, -anyio/_core/__pycache__/_typedattr.cpython-313.pyc,, -anyio/_core/_asyncio_selector_thread.py,sha256=2PdxFM3cs02Kp6BSppbvmRT7q7asreTW5FgBxEsflBo,5626 -anyio/_core/_contextmanagers.py,sha256=YInBCabiEeS-UaP_Jdxa1CaFC71ETPW8HZTHIM8Rsc8,7215 -anyio/_core/_eventloop.py,sha256=ByZUeJD9alMfcyTseRo5IzTO0IltEul_Gyq9iqSjqDk,6658 -anyio/_core/_exceptions.py,sha256=OfzLO4Z3Hog1TnipbIn72YNtkoYxS4lHW9MqKDeGc88,4936 -anyio/_core/_fileio.py,sha256=hHfyV0bXDL-R2ZNnInwse3nmTAd36AIz1cBxgmAwzAQ,31358 -anyio/_core/_resources.py,sha256=NbmU5O5UX3xEyACnkmYX28Fmwdl-f-ny0tHym26e0w0,435 -anyio/_core/_signals.py,sha256=mjTBB2hTKNPRlU0IhnijeQedpWOGERDiMjSlJQsFrug,1016 -anyio/_core/_sockets.py,sha256=9FU423j52XBBfGVr6MdzPTdyw8bGrzApZ5m338-AtsY,35286 -anyio/_core/_streams.py,sha256=FczFwIgDpnkK0bODWJXMpsUJYdvAD04kaUaGzJU8DK0,1806 -anyio/_core/_subprocesses.py,sha256=tkmkPKEkEaiMD8C9WRZBlmgjOYRDRbZdte6e-unay2E,7916 -anyio/_core/_synchronization.py,sha256=U14eUp9tqcP95OcCG7s3A1MZU9WLw84lOS4YB-H795s,21591 -anyio/_core/_tasks.py,sha256=ELL2jscaSW0Jw_xA6MtQlm3xwvFEzjTbc1u9Tteyt0I,13244 -anyio/_core/_tempfile.py,sha256=jE2w59FRF3yRo4vjkjfZF2YcqsBZvc66VWRwrJGDYGk,19624 -anyio/_core/_testing.py,sha256=u7MPqGXwpTxqI7hclSdNA30z2GH1Nw258uwKvy_RfBg,2340 -anyio/_core/_typedattr.py,sha256=P4ozZikn3-DbpoYcvyghS_FOYAgbmUxeoU8-L_07pZM,2508 -anyio/abc/__init__.py,sha256=6mWhcl_pGXhrgZVHP_TCfMvIXIOp9mroEFM90fYCU_U,2869 -anyio/abc/__pycache__/__init__.cpython-313.pyc,, -anyio/abc/__pycache__/_eventloop.cpython-313.pyc,, -anyio/abc/__pycache__/_resources.cpython-313.pyc,, -anyio/abc/__pycache__/_sockets.cpython-313.pyc,, -anyio/abc/__pycache__/_streams.cpython-313.pyc,, -anyio/abc/__pycache__/_subprocesses.cpython-313.pyc,, -anyio/abc/__pycache__/_tasks.cpython-313.pyc,, -anyio/abc/__pycache__/_testing.cpython-313.pyc,, -anyio/abc/_eventloop.py,sha256=OqWYSEj0TmwL_xniCJt3_jHFWsuMk9THk8tCTGsKapI,10681 -anyio/abc/_resources.py,sha256=DrYvkNN1hH6Uvv5_5uKySvDsnknGVDe8FCKfko0VtN8,783 -anyio/abc/_sockets.py,sha256=OmVDrfemVvF9c5K1tpBgQyV6fn5v0XyCExLAqBOGz9o,13124 -anyio/abc/_streams.py,sha256=HYvna1iZbWcwLROTO6IhLX79RTRLPShZMWe0sG1q54I,7481 -anyio/abc/_subprocesses.py,sha256=cumAPJTktOQtw63IqG0lDpyZqu_l1EElvQHMiwJgL08,2067 -anyio/abc/_tasks.py,sha256=m-FtE4phxeNIELSG7A3H7VUz3jA2Ib5J2JIew8-PS6o,6642 -anyio/abc/_testing.py,sha256=9YYM2AXsYFvf4PLjUEr6yRxDiUeB5QbY_gOg0X_C6lY,2034 -anyio/from_thread.py,sha256=JYsbaCaIB_Iit6kNhtXSteJGt4PcQ7ncq0nIpcelIrg,19265 -anyio/functools.py,sha256=T4JS8IXq-x1S0Lbo2owF8l9fza2KypO147QLeyz4cjs,11797 -anyio/itertools.py,sha256=QV-9mnRCr2yBph8g01QFvN-bQ_Yle-8Sl13YSydBlMI,16168 -anyio/lowlevel.py,sha256=WPtppHfI2qs1nokzjn8elL8LvyqI05AK5Zslhlo71A4,6242 -anyio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -anyio/pytest_plugin.py,sha256=paMpI_VMNQf2bir0LfvgMpXSiYJoHDzWdKUVTyoHmvQ,13609 -anyio/streams/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -anyio/streams/__pycache__/__init__.cpython-313.pyc,, -anyio/streams/__pycache__/buffered.cpython-313.pyc,, -anyio/streams/__pycache__/file.cpython-313.pyc,, -anyio/streams/__pycache__/memory.cpython-313.pyc,, -anyio/streams/__pycache__/stapled.cpython-313.pyc,, -anyio/streams/__pycache__/text.cpython-313.pyc,, -anyio/streams/__pycache__/tls.cpython-313.pyc,, -anyio/streams/buffered.py,sha256=v3xKtjFHgNV41g2SvMAkA_qd2t9WYlCI1_lNGCAatw0,6650 -anyio/streams/file.py,sha256=msnrotVKGMQomUu_Rj2qz9MvIdUp6d3JGr7MOEO8kV4,4428 -anyio/streams/memory.py,sha256=F0zwzvFJKAhX_LRZGoKzzqDC2oMM-f-yyTBrEYEGOaU,10740 -anyio/streams/stapled.py,sha256=T8Xqwf8K6EgURPxbt1N4i7A8BAk-gScv-GRhjLXIf_o,4390 -anyio/streams/text.py,sha256=BcVAGJw1VRvtIqnv-o0Rb0pwH7p8vwlvl21xHq522ag,5765 -anyio/streams/tls.py,sha256=DQVkXUvsTEYKkBO8dlVU7j_5H8QOtLy4sGi1Wrjqevo,15303 -anyio/to_interpreter.py,sha256=_mLngrMy97TMR6VbW4Y6YzDUk9ZuPcQMPlkuyRh3C9k,7100 -anyio/to_process.py,sha256=68qhLfce7MeXysid4fOpmhfWkgdo7Z7-9BC0VyUciIE,9809 -anyio/to_thread.py,sha256=f6h_k2d743GBv9FhAnhM_YpTvWgIrzBy9cOE0eJ1UJw,2693 diff --git a/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/WHEEL b/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/WHEEL deleted file mode 100644 index 14a883f..0000000 --- a/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (82.0.1) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/entry_points.txt b/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/entry_points.txt deleted file mode 100644 index 44dd9bd..0000000 --- a/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[pytest11] -anyio = anyio.pytest_plugin diff --git a/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/licenses/LICENSE b/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/licenses/LICENSE deleted file mode 100644 index 104eebf..0000000 --- a/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2018 Alex Grönholm - -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/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/top_level.txt b/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/top_level.txt deleted file mode 100644 index c77c069..0000000 --- a/server/venv/Lib/site-packages/anyio-4.14.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -anyio diff --git a/server/venv/Lib/site-packages/anyio/__init__.py b/server/venv/Lib/site-packages/anyio/__init__.py deleted file mode 100644 index 2502c76..0000000 --- a/server/venv/Lib/site-packages/anyio/__init__.py +++ /dev/null @@ -1,115 +0,0 @@ -from __future__ import annotations - -from ._core._contextmanagers import AsyncContextManagerMixin as AsyncContextManagerMixin -from ._core._contextmanagers import ContextManagerMixin as ContextManagerMixin -from ._core._eventloop import current_time as current_time -from ._core._eventloop import get_all_backends as get_all_backends -from ._core._eventloop import get_available_backends as get_available_backends -from ._core._eventloop import get_cancelled_exc_class as get_cancelled_exc_class -from ._core._eventloop import run as run -from ._core._eventloop import sleep as sleep -from ._core._eventloop import sleep_forever as sleep_forever -from ._core._eventloop import sleep_until as sleep_until -from ._core._exceptions import BrokenResourceError as BrokenResourceError -from ._core._exceptions import BrokenWorkerInterpreter as BrokenWorkerInterpreter -from ._core._exceptions import BrokenWorkerProcess as BrokenWorkerProcess -from ._core._exceptions import BusyResourceError as BusyResourceError -from ._core._exceptions import ClosedResourceError as ClosedResourceError -from ._core._exceptions import ConnectionFailed as ConnectionFailed -from ._core._exceptions import DelimiterNotFound as DelimiterNotFound -from ._core._exceptions import EndOfStream as EndOfStream -from ._core._exceptions import IncompleteRead as IncompleteRead -from ._core._exceptions import NoEventLoopError as NoEventLoopError -from ._core._exceptions import RunFinishedError as RunFinishedError -from ._core._exceptions import TaskCancelled as TaskCancelled -from ._core._exceptions import TaskFailed as TaskFailed -from ._core._exceptions import TaskNotFinished as TaskNotFinished -from ._core._exceptions import TypedAttributeLookupError as TypedAttributeLookupError -from ._core._exceptions import WouldBlock as WouldBlock -from ._core._fileio import AsyncFile as AsyncFile -from ._core._fileio import Path as Path -from ._core._fileio import open_file as open_file -from ._core._fileio import wrap_file as wrap_file -from ._core._resources import aclose_forcefully as aclose_forcefully -from ._core._signals import open_signal_receiver as open_signal_receiver -from ._core._sockets import TCPConnectable as TCPConnectable -from ._core._sockets import UNIXConnectable as UNIXConnectable -from ._core._sockets import as_connectable as as_connectable -from ._core._sockets import connect_tcp as connect_tcp -from ._core._sockets import connect_unix as connect_unix -from ._core._sockets import create_connected_udp_socket as create_connected_udp_socket -from ._core._sockets import ( - create_connected_unix_datagram_socket as create_connected_unix_datagram_socket, -) -from ._core._sockets import create_tcp_listener as create_tcp_listener -from ._core._sockets import create_udp_socket as create_udp_socket -from ._core._sockets import create_unix_datagram_socket as create_unix_datagram_socket -from ._core._sockets import create_unix_listener as create_unix_listener -from ._core._sockets import getaddrinfo as getaddrinfo -from ._core._sockets import getnameinfo as getnameinfo -from ._core._sockets import notify_closing as notify_closing -from ._core._sockets import wait_readable as wait_readable -from ._core._sockets import wait_socket_readable as wait_socket_readable -from ._core._sockets import wait_socket_writable as wait_socket_writable -from ._core._sockets import wait_writable as wait_writable -from ._core._streams import create_memory_object_stream as create_memory_object_stream -from ._core._subprocesses import open_process as open_process -from ._core._subprocesses import run_process as run_process -from ._core._synchronization import CapacityLimiter as CapacityLimiter -from ._core._synchronization import ( - CapacityLimiterStatistics as CapacityLimiterStatistics, -) -from ._core._synchronization import Condition as Condition -from ._core._synchronization import ConditionStatistics as ConditionStatistics -from ._core._synchronization import Event as Event -from ._core._synchronization import EventStatistics as EventStatistics -from ._core._synchronization import Lock as Lock -from ._core._synchronization import LockStatistics as LockStatistics -from ._core._synchronization import ResourceGuard as ResourceGuard -from ._core._synchronization import Semaphore as Semaphore -from ._core._synchronization import SemaphoreStatistics as SemaphoreStatistics -from ._core._tasks import TASK_STATUS_IGNORED as TASK_STATUS_IGNORED -from ._core._tasks import CancelScope as CancelScope -from ._core._tasks import TaskHandle as TaskHandle -from ._core._tasks import create_task_group as create_task_group -from ._core._tasks import current_effective_deadline as current_effective_deadline -from ._core._tasks import fail_after as fail_after -from ._core._tasks import move_on_after as move_on_after -from ._core._tempfile import NamedTemporaryFile as NamedTemporaryFile -from ._core._tempfile import SpooledTemporaryFile as SpooledTemporaryFile -from ._core._tempfile import TemporaryDirectory as TemporaryDirectory -from ._core._tempfile import TemporaryFile as TemporaryFile -from ._core._tempfile import gettempdir as gettempdir -from ._core._tempfile import gettempdirb as gettempdirb -from ._core._tempfile import mkdtemp as mkdtemp -from ._core._tempfile import mkstemp as mkstemp -from ._core._testing import TaskInfo as TaskInfo -from ._core._testing import get_current_task as get_current_task -from ._core._testing import get_running_tasks as get_running_tasks -from ._core._testing import wait_all_tasks_blocked as wait_all_tasks_blocked -from ._core._typedattr import TypedAttributeProvider as TypedAttributeProvider -from ._core._typedattr import TypedAttributeSet as TypedAttributeSet -from ._core._typedattr import typed_attribute as typed_attribute - -# Re-export imports so they look like they live directly in this package -for __value in list(locals().values()): - if getattr(__value, "__module__", "").startswith("anyio."): - __value.__module__ = __name__ - - -del __value - - -def __getattr__(attr: str) -> type[BrokenWorkerInterpreter]: - """Support deprecated aliases.""" - if attr == "BrokenWorkerIntepreter": - import warnings - - warnings.warn( - "The 'BrokenWorkerIntepreter' alias is deprecated, use 'BrokenWorkerInterpreter' instead.", - DeprecationWarning, - stacklevel=2, - ) - return BrokenWorkerInterpreter - - raise AttributeError(f"module {__name__!r} has no attribute {attr!r}") diff --git a/server/venv/Lib/site-packages/anyio/_backends/__init__.py b/server/venv/Lib/site-packages/anyio/_backends/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/venv/Lib/site-packages/anyio/_backends/_asyncio.py b/server/venv/Lib/site-packages/anyio/_backends/_asyncio.py deleted file mode 100644 index a51a150..0000000 --- a/server/venv/Lib/site-packages/anyio/_backends/_asyncio.py +++ /dev/null @@ -1,3073 +0,0 @@ -from __future__ import annotations - -import array -import asyncio -import concurrent.futures -import contextvars -import math -import os -import socket -import sys -import threading -import weakref -from asyncio import ( - AbstractEventLoop, - CancelledError, - all_tasks, - create_task, - current_task, - get_running_loop, - sleep, -) -from asyncio.base_events import _run_until_complete_cb # type: ignore[attr-defined] -from collections import OrderedDict, deque -from collections.abc import ( - AsyncGenerator, - AsyncIterator, - Awaitable, - Callable, - Collection, - Coroutine, - Iterable, - Sequence, -) -from concurrent.futures import Future -from contextlib import AbstractContextManager -from contextvars import Context, copy_context -from dataclasses import dataclass, field -from functools import partial, wraps -from inspect import ( - CORO_RUNNING, - CORO_SUSPENDED, - getcoroutinestate, -) -from io import IOBase -from os import PathLike -from queue import Queue -from signal import Signals -from socket import AddressFamily, SocketKind -from threading import Thread -from types import CodeType, TracebackType -from typing import ( - IO, - TYPE_CHECKING, - Any, - Literal, - ParamSpec, - TypeVar, - cast, -) -from weakref import WeakKeyDictionary - -from .. import ( - CapacityLimiterStatistics, - EventStatistics, - LockStatistics, - TaskInfo, - abc, -) -from .._core._eventloop import ( - claim_worker_thread, - set_current_async_library, - threadlocals, -) -from .._core._exceptions import ( - BrokenResourceError, - BusyResourceError, - ClosedResourceError, - EndOfStream, - RunFinishedError, - WouldBlock, -) -from .._core._sockets import convert_ipv6_sockaddr -from .._core._streams import create_memory_object_stream -from .._core._synchronization import ( - CapacityLimiter as BaseCapacityLimiter, -) -from .._core._synchronization import Event as BaseEvent -from .._core._synchronization import Lock as BaseLock -from .._core._synchronization import ( - ResourceGuard, - SemaphoreStatistics, -) -from .._core._synchronization import Semaphore as BaseSemaphore -from .._core._tasks import CancelScope as BaseCancelScope -from .._core._tasks import TaskHandle -from ..abc import ( - AsyncBackend, - IPSockAddrType, - SocketListener, - UDPPacketType, - UNIXDatagramPacketType, -) -from ..abc._eventloop import StrOrBytesPath -from ..abc._tasks import call_for_coroutine, get_callable_name -from ..lowlevel import RunVar -from ..streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream - -if TYPE_CHECKING: - from _typeshed import FileDescriptorLike -else: - FileDescriptorLike = object - -if sys.version_info >= (3, 11): - from asyncio import Runner - from typing import TypeVarTuple, Unpack -else: - import contextvars - import enum - import signal - from asyncio import coroutines, events, exceptions, tasks - - from exceptiongroup import BaseExceptionGroup - from typing_extensions import TypeVarTuple, Unpack - - class _State(enum.Enum): - CREATED = "created" - INITIALIZED = "initialized" - CLOSED = "closed" - - class Runner: - # Copied from CPython 3.11 - def __init__( - self, - *, - debug: bool | None = None, - loop_factory: Callable[[], AbstractEventLoop] | None = None, - ): - self._state = _State.CREATED - self._debug = debug - self._loop_factory = loop_factory - self._loop: AbstractEventLoop | None = None - self._context = None - self._interrupt_count = 0 - self._set_event_loop = False - - def __enter__(self) -> Runner: - self._lazy_init() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.close() - - def close(self) -> None: - """Shutdown and close event loop.""" - loop = self._loop - if self._state is not _State.INITIALIZED or loop is None: - return - try: - _cancel_all_tasks(loop) - loop.run_until_complete(loop.shutdown_asyncgens()) - if hasattr(loop, "shutdown_default_executor"): - loop.run_until_complete(loop.shutdown_default_executor()) - else: - loop.run_until_complete(_shutdown_default_executor(loop)) - finally: - if self._set_event_loop: - events.set_event_loop(None) - loop.close() - self._loop = None - self._state = _State.CLOSED - - def get_loop(self) -> AbstractEventLoop: - """Return embedded event loop.""" - self._lazy_init() - return self._loop - - def run(self, coro: Coroutine[T_Retval], *, context=None) -> T_Retval: - """Run a coroutine inside the embedded event loop.""" - if not coroutines.iscoroutine(coro): - raise ValueError(f"a coroutine was expected, got {coro!r}") - - if events._get_running_loop() is not None: - # fail fast with short traceback - raise RuntimeError( - "Runner.run() cannot be called from a running event loop" - ) - - self._lazy_init() - - if context is None: - context = self._context - task = context.run(self._loop.create_task, coro) - - if ( - threading.current_thread() is threading.main_thread() - and signal.getsignal(signal.SIGINT) is signal.default_int_handler - ): - sigint_handler = partial(self._on_sigint, main_task=task) - try: - signal.signal(signal.SIGINT, sigint_handler) - except ValueError: - # `signal.signal` may throw if `threading.main_thread` does - # not support signals (e.g. embedded interpreter with signals - # not registered - see gh-91880) - sigint_handler = None - else: - sigint_handler = None - - self._interrupt_count = 0 - try: - return self._loop.run_until_complete(task) - except exceptions.CancelledError: - if self._interrupt_count > 0: - uncancel = getattr(task, "uncancel", None) - if uncancel is not None and uncancel() == 0: - raise KeyboardInterrupt # noqa: B904 - raise # CancelledError - finally: - if ( - sigint_handler is not None - and signal.getsignal(signal.SIGINT) is sigint_handler - ): - signal.signal(signal.SIGINT, signal.default_int_handler) - - def _lazy_init(self) -> None: - if self._state is _State.CLOSED: - raise RuntimeError("Runner is closed") - if self._state is _State.INITIALIZED: - return - if self._loop_factory is None: - self._loop = events.new_event_loop() - if not self._set_event_loop: - # Call set_event_loop only once to avoid calling - # attach_loop multiple times on child watchers - events.set_event_loop(self._loop) - self._set_event_loop = True - else: - self._loop = self._loop_factory() - if self._debug is not None: - self._loop.set_debug(self._debug) - self._context = contextvars.copy_context() - self._state = _State.INITIALIZED - - def _on_sigint(self, signum, frame, main_task: asyncio.Task) -> None: - self._interrupt_count += 1 - if self._interrupt_count == 1 and not main_task.done(): - main_task.cancel() - # wakeup loop if it is blocked by select() with long timeout - self._loop.call_soon_threadsafe(lambda: None) - return - raise KeyboardInterrupt() - - def _cancel_all_tasks(loop: AbstractEventLoop) -> None: - to_cancel = tasks.all_tasks(loop) - if not to_cancel: - return - - for task in to_cancel: - task.cancel() - - loop.run_until_complete(tasks.gather(*to_cancel, return_exceptions=True)) - - for task in to_cancel: - if task.cancelled(): - continue - if task.exception() is not None: - loop.call_exception_handler( - { - "message": "unhandled exception during asyncio.run() shutdown", - "exception": task.exception(), - "task": task, - } - ) - - async def _shutdown_default_executor(loop: AbstractEventLoop) -> None: - """Schedule the shutdown of the default executor.""" - - def _do_shutdown(future: asyncio.futures.Future) -> None: - try: - loop._default_executor.shutdown(wait=True) # type: ignore[attr-defined] - loop.call_soon_threadsafe(future.set_result, None) - except Exception as ex: - loop.call_soon_threadsafe(future.set_exception, ex) - - loop._executor_shutdown_called = True - if loop._default_executor is None: - return - future = loop.create_future() - thread = threading.Thread(target=_do_shutdown, args=(future,)) - thread.start() - try: - await future - finally: - thread.join() - - -T_Retval = TypeVar("T_Retval") -T_co = TypeVar("T_co", covariant=True) -T_contra = TypeVar("T_contra", contravariant=True) -PosArgsT = TypeVarTuple("PosArgsT") -P = ParamSpec("P") - -_root_task: RunVar[asyncio.Task | None] = RunVar("_root_task") - - -def find_root_task() -> asyncio.Task: - root_task = _root_task.get(None) - if root_task is not None and not root_task.done(): - return root_task - - # Look for a task that has been started via run_until_complete() - for task in all_tasks(): - if task._callbacks and not task.done(): - callbacks = [cb for cb, context in task._callbacks] - for cb in callbacks: - if ( - cb is _run_until_complete_cb - or getattr(cb, "__module__", None) == "uvloop.loop" - ): - _root_task.set(task) - return task - - # Look up the topmost task in the AnyIO task tree, if possible - task = cast(asyncio.Task, current_task()) - state = _task_states.get(task) - if state: - cancel_scope = state.cancel_scope - while cancel_scope and cancel_scope._parent_scope is not None: - cancel_scope = cancel_scope._parent_scope - - if cancel_scope is not None: - return cast(asyncio.Task, cancel_scope._host_task) - - return task - - -# -# Event loop -# - -_run_vars: WeakKeyDictionary[asyncio.AbstractEventLoop, Any] = WeakKeyDictionary() - - -def _task_started(task: asyncio.Task) -> bool: - """Return ``True`` if the task has been started and has not finished.""" - # The task coro should never be None here, as we never add finished tasks to the - # task list - coro = task.get_coro() - assert coro is not None - return getcoroutinestate(coro) in (CORO_RUNNING, CORO_SUSPENDED) - - -# -# Timeouts and cancellation -# - - -def is_anyio_cancellation(exc: CancelledError) -> bool: - # Sometimes third party frameworks catch a CancelledError and raise a new one, so as - # a workaround we have to look at the previous ones in __context__ too for a - # matching cancel message - while True: - if ( - exc.args - and isinstance(exc.args[0], str) - and exc.args[0].startswith("Cancelled via cancel scope ") - ): - return True - - if isinstance(exc.__context__, CancelledError): - exc = exc.__context__ - continue - - return False - - -class CancelScope(BaseCancelScope): - __slots__ = ( - "_active", - "_cancel_called", - "_cancel_handle", - "_cancel_reason", - "_cancelled_caught", - "_child_scopes", - "_deadline", - "_host_task", - "_parent_scope", - "_pending_uncancellations", - "_shield", - "_tasks", - "_timeout_handle", - ) - - def __new__( - cls, *, deadline: float = math.inf, shield: bool = False - ) -> CancelScope: - return object.__new__(cls) - - def __init__(self, deadline: float = math.inf, shield: bool = False): - self._deadline = deadline - self._shield = shield - self._parent_scope: CancelScope | None = None - self._child_scopes: set[CancelScope] = set() - self._cancel_called = False - self._cancel_reason: str | None = None - self._cancelled_caught = False - self._active = False - self._timeout_handle: asyncio.TimerHandle | None = None - self._cancel_handle: asyncio.Handle | None = None - self._tasks: set[asyncio.Task] = set() - self._host_task: asyncio.Task | None = None - if sys.version_info >= (3, 11): - self._pending_uncancellations: int | None = 0 - else: - self._pending_uncancellations = None - - def __enter__(self) -> CancelScope: - if self._active: - raise RuntimeError( - "Each CancelScope may only be used for a single 'with' block" - ) - - self._host_task = host_task = cast(asyncio.Task, current_task()) - self._tasks.add(host_task) - try: - task_state = _task_states[host_task] - except KeyError: - task_state = TaskState(None, self) - _task_states[host_task] = task_state - else: - self._parent_scope = task_state.cancel_scope - task_state.cancel_scope = self - if self._parent_scope is not None: - # If using an eager task factory, the parent scope may not even contain - # the host task - self._parent_scope._child_scopes.add(self) - self._parent_scope._tasks.discard(host_task) - - self._timeout() - self._active = True - - # Start cancelling the host task if the scope was cancelled before entering - if self._cancel_called: - self._deliver_cancellation(self) - - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - del exc_tb - - if not self._active: - raise RuntimeError("This cancel scope is not active") - if current_task() is not self._host_task: - raise RuntimeError( - "Attempted to exit cancel scope in a different task than it was " - "entered in" - ) - - assert self._host_task is not None - host_task_state = _task_states.get(self._host_task) - if host_task_state is None or host_task_state.cancel_scope is not self: - raise RuntimeError( - "Attempted to exit a cancel scope that isn't the current tasks's " - "current cancel scope" - ) - - try: - self._active = False - if self._timeout_handle: - self._timeout_handle.cancel() - self._timeout_handle = None - - self._tasks.remove(self._host_task) - if self._parent_scope is not None: - self._parent_scope._child_scopes.remove(self) - self._parent_scope._tasks.add(self._host_task) - - host_task_state.cancel_scope = self._parent_scope - - # Restart the cancellation effort in the closest visible, cancelled parent - # scope if necessary - self._restart_cancellation_in_parent() - - # We only swallow the exception iff it was an AnyIO CancelledError, either - # directly as exc_val or inside an exception group and there are no cancelled - # parent cancel scopes visible to us here - if self._cancel_called and not self._parent_cancellation_is_visible_to_us: - # For each level-cancel() call made on the host task, call uncancel() - while self._pending_uncancellations: - self._host_task.uncancel() - self._pending_uncancellations -= 1 - - # Update cancelled_caught and check for exceptions we must not swallow - if isinstance(exc_val, BaseExceptionGroup): - cancelleds_caught, remaining = exc_val.split( - lambda exc: ( - isinstance(exc, CancelledError) - and is_anyio_cancellation(exc) - ) - ) - - if cancelleds_caught is None: - return False - - self._cancelled_caught = True - - if remaining is None: - return True - - context = remaining.__context__ - try: - # Preserve __cause__ and __suppress_context__ by avoiding `raise - # ... from ...` - raise remaining - finally: - # Preserve __context__ - remaining.__context__ = context - del context - else: - if isinstance(exc_val, CancelledError) and is_anyio_cancellation( - exc_val - ): - self._cancelled_caught = True - return True - else: - return False - else: - if self._pending_uncancellations: - assert self._parent_scope is not None - assert self._parent_scope._pending_uncancellations is not None - self._parent_scope._pending_uncancellations += ( - self._pending_uncancellations - ) - self._pending_uncancellations = 0 - - return False - finally: - self._host_task = None - del exc_val - - @property - def _effectively_cancelled(self) -> bool: - cancel_scope: CancelScope | None = self - while cancel_scope is not None: - if cancel_scope._cancel_called: - return True - - if cancel_scope.shield: - return False - - cancel_scope = cancel_scope._parent_scope - - return False - - @property - def _parent_cancellation_is_visible_to_us(self) -> bool: - return ( - self._parent_scope is not None - and not self.shield - and self._parent_scope._effectively_cancelled - ) - - def _timeout(self) -> None: - if self._deadline != math.inf: - loop = get_running_loop() - if loop.time() >= self._deadline: - self.cancel("deadline exceeded") - else: - self._timeout_handle = loop.call_at(self._deadline, self._timeout) - - def _deliver_cancellation(self, origin: CancelScope) -> bool: - """ - Deliver cancellation to directly contained tasks and nested cancel scopes. - - Schedule another run at the end if we still have tasks eligible for - cancellation. - - :param origin: the cancel scope that originated the cancellation - :return: ``True`` if the delivery needs to be retried on the next cycle - - """ - should_retry = False - current = current_task() - for task in self._tasks: - should_retry = True - if task._must_cancel: # type: ignore[attr-defined] - continue - - # The task is eligible for cancellation if it has started - if task is not current and (task is self._host_task or _task_started(task)): - waiter = task._fut_waiter # type: ignore[attr-defined] - if not isinstance(waiter, asyncio.Future) or not waiter.done(): - task.cancel(origin._cancel_reason) - if ( - task is origin._host_task - and origin._pending_uncancellations is not None - ): - origin._pending_uncancellations += 1 - - # Deliver cancellation to child scopes that aren't shielded or running their own - # cancellation callbacks - for scope in self._child_scopes: - if not scope._shield and not scope.cancel_called: - should_retry = scope._deliver_cancellation(origin) or should_retry - - # Schedule another callback if there are still tasks left - if origin is self: - if should_retry: - self._cancel_handle = get_running_loop().call_soon( - self._deliver_cancellation, origin - ) - else: - self._cancel_handle = None - - return should_retry - - def _restart_cancellation_in_parent(self) -> None: - """ - Restart the cancellation effort in the closest directly cancelled parent scope. - - """ - scope = self._parent_scope - while scope is not None: - if scope._cancel_called: - if scope._cancel_handle is None: - scope._deliver_cancellation(scope) - - break - - # No point in looking beyond any shielded scope - if scope._shield: - break - - scope = scope._parent_scope - - def cancel(self, reason: str | None = None) -> None: - if not self._cancel_called: - if self._timeout_handle: - self._timeout_handle.cancel() - self._timeout_handle = None - - self._cancel_called = True - self._cancel_reason = f"Cancelled via cancel scope {id(self):x}" - if task := current_task(): - self._cancel_reason += f" by {task}" - - if reason: - self._cancel_reason += f"; reason: {reason}" - - if self._host_task is not None: - self._deliver_cancellation(self) - - @property - def deadline(self) -> float: - return self._deadline - - @deadline.setter - def deadline(self, value: float) -> None: - self._deadline = float(value) - if self._timeout_handle is not None: - self._timeout_handle.cancel() - self._timeout_handle = None - - if self._active and not self._cancel_called: - self._timeout() - - @property - def cancel_called(self) -> bool: - return self._cancel_called - - @property - def cancelled_caught(self) -> bool: - return self._cancelled_caught - - @property - def shield(self) -> bool: - return self._shield - - @shield.setter - def shield(self, value: bool) -> None: - if self._shield != value: - self._shield = value - if not value: - self._restart_cancellation_in_parent() - - -# -# Task states -# - - -class TaskState: - """ - Encapsulates auxiliary task information that cannot be added to the Task instance - itself because there are no guarantees about its implementation. - """ - - __slots__ = "parent_id", "cancel_scope", "__weakref__" - - def __init__(self, parent_id: int | None, cancel_scope: CancelScope | None): - self.parent_id = parent_id - self.cancel_scope = cancel_scope - - -_task_states: WeakKeyDictionary[asyncio.Task, TaskState] = WeakKeyDictionary() - - -# -# Task groups -# - - -class _AsyncioTaskStatus(abc.TaskStatus): - def __init__(self, future: asyncio.Future, parent_id: int): - self._future = future - self._parent_id = parent_id - - def started(self, value: T_contra | None = None) -> None: - try: - self._future.set_result(value) - except asyncio.InvalidStateError: - if not self._future.cancelled(): - raise RuntimeError( - "called 'started' twice on the same task status" - ) from None - - task = cast(asyncio.Task, current_task()) - _task_states[task].parent_id = self._parent_id - - -if sys.version_info >= (3, 12): - _eager_task_factory_code: CodeType | None = asyncio.eager_task_factory.__code__ -else: - _eager_task_factory_code = None - - -class TaskGroup(abc.TaskGroup): - def __init__(self) -> None: - self.cancel_scope: CancelScope = CancelScope() - self._entered = False - self._exceptions: list[BaseException] = [] - self._tasks: set[asyncio.Task] = set() - self._on_completed_fut: asyncio.Future[None] | None = None - - async def __aenter__(self) -> TaskGroup: - if self._entered: - raise RuntimeError("TaskGroup cannot be entered more than once") - - self._entered = True - - self.cancel_scope.__enter__() - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - try: - if exc_val is not None: - self.cancel_scope.cancel() - if not isinstance(exc_val, CancelledError): - self._exceptions.append(exc_val) - - loop = get_running_loop() - try: - if self._tasks: - with CancelScope() as wait_scope: - while self._tasks: - self._on_completed_fut = loop.create_future() - - try: - await self._on_completed_fut - except CancelledError as exc: - # Shield the scope against further cancellation attempts, - # as they're not productive (#695) - wait_scope.shield = True - self.cancel_scope.cancel() - - # Set exc_val from the cancellation exception if it was - # previously unset. However, we should not replace a native - # cancellation exception with one raise by a cancel scope. - if exc_val is None or ( - isinstance(exc_val, CancelledError) - and not is_anyio_cancellation(exc) - ): - exc_val = exc - - self._on_completed_fut = None - else: - # If there are no child tasks to wait on, run at least one checkpoint - # anyway - await AsyncIOBackend.cancel_shielded_checkpoint() - - if self._exceptions: - # The exception that got us here should already have been - # added to self._exceptions so it's ok to break exception - # chaining and avoid adding a "During handling of above..." - # for each nesting level. - raise BaseExceptionGroup( - "unhandled errors in a TaskGroup", self._exceptions - ) from None - elif exc_val: - raise exc_val - except BaseException as exc: - if self.cancel_scope.__exit__(type(exc), exc, exc.__traceback__): - return True - - raise - - return self.cancel_scope.__exit__(exc_type, exc_val, exc_tb) - finally: - del exc_val, exc_tb, self._exceptions - - def _spawn( - self, - coro: Coroutine[Any, Any, T_co], - name: object, - task_status_future: asyncio.Future | None = None, - ) -> TaskHandle[T_co]: - def task_done(_task: asyncio.Task) -> None: - if sys.version_info >= (3, 14) and self.cancel_scope._host_task is not None: - asyncio.future_discard_from_awaited_by( - _task, self.cancel_scope._host_task - ) - - task_state = _task_states[_task] - assert task_state.cancel_scope is not None - assert _task in task_state.cancel_scope._tasks - task_state.cancel_scope._tasks.remove(_task) - self._tasks.remove(task) - del _task_states[_task] - - if self._on_completed_fut is not None and not self._tasks: - try: - self._on_completed_fut.set_result(None) - except asyncio.InvalidStateError: - pass - - try: - exc = _task.exception() - except CancelledError as e: - while isinstance(e.__context__, CancelledError): - e = e.__context__ - - exc = e - - if exc is not None: - # The future can only be in the cancelled state if the host task was - # cancelled, so return immediately instead of adding one more - # CancelledError to the exceptions list - if task_status_future is not None and task_status_future.cancelled(): - return - - if task_status_future is None or task_status_future.done(): - if not isinstance(exc, CancelledError): - self._exceptions.append(exc) - - if not self.cancel_scope._effectively_cancelled: - self.cancel_scope.cancel() - else: - task_status_future.set_exception(exc) - elif task_status_future is not None and not task_status_future.done(): - task_status_future.set_exception( - RuntimeError("Child exited without calling task_status.started()") - ) - - if task_status_future: - parent_id = id(current_task()) - else: - parent_id = id(self.cancel_scope._host_task) - - handle = TaskHandle(coro, name) - loop = asyncio.get_running_loop() - wrapper_coro = handle._run_coro() - if ( - (factory := loop.get_task_factory()) - and getattr(factory, "__code__", None) is _eager_task_factory_code - and (closure := getattr(factory, "__closure__", None)) - ): - custom_task_constructor = closure[0].cell_contents - task = custom_task_constructor(wrapper_coro, loop=loop, name=handle.name) - else: - task = loop.create_task(wrapper_coro, name=handle.name) - - # Make the spawned task inherit the task group's cancel scope - _task_states[task] = TaskState( - parent_id=parent_id, cancel_scope=self.cancel_scope - ) - self.cancel_scope._tasks.add(task) - self._tasks.add(task) - if sys.version_info >= (3, 14) and self.cancel_scope._host_task is not None: - asyncio.future_add_to_awaited_by(task, self.cancel_scope._host_task) - - task.add_done_callback(task_done) - return handle - - def create_task( - self, - coro: Coroutine[Any, Any, T_co], - *, - name: object = None, - context: Context | None = None, - ) -> TaskHandle[T_co]: - if not isinstance(coro, Coroutine): - raise TypeError(f"expected a coroutine, got {coro.__class__.__qualname__}") - - if not self._entered or not self.cancel_scope._active: - coro.close() - raise RuntimeError( - "This task group is not active; no new tasks can be started." - ) - - if context is not None: - return context.run(self._spawn, coro, name=name) - else: - return self._spawn(coro, name=name) - - async def start( - self, - func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]], - *args: Unpack[PosArgsT], - name: object = None, - return_handle: Literal[False] | Literal[True] = False, - ) -> Any: - if not self._entered or not self.cancel_scope._active: - raise RuntimeError( - "This task group is not active; no new tasks can be started." - ) - - future: asyncio.Future = asyncio.Future() - final_name = get_callable_name(func, name) - task_status = _AsyncioTaskStatus(future, id(self.cancel_scope._host_task)) - coro = call_for_coroutine(func, args, task_status=task_status) - handle = self._spawn(coro, final_name, future) - - # If the task raises an exception after sending a start value without a switch - # point between, the task group is cancelled and this method never proceeds to - # process the completed future. That's why we have to have a shielded cancel - # scope here. - try: - await future - except BaseException: - if handle.status is TaskHandle.Status.PENDING: - # Cancel the task and wait for it to exit before returning - handle.cancel() - with CancelScope(shield=True): - await handle.wait() - - raise - - if return_handle: - handle._start_value = future.result() - return handle - else: - return future.result() - - -# -# Threads -# - -_Retval_Queue_Type = tuple[T_Retval | None, BaseException | None] - - -class WorkerThread(Thread): - MAX_IDLE_TIME = 10 # seconds - - def __init__( - self, - root_task: asyncio.Task, - workers: set[WorkerThread], - idle_workers: deque[WorkerThread], - ): - super().__init__(name="AnyIO worker thread") - self.root_task = root_task - self.workers = workers - self.idle_workers = idle_workers - self.loop = root_task._loop - self.queue: Queue[ - tuple[Context, Callable, tuple, asyncio.Future, CancelScope] | None - ] = Queue(2) - self.idle_since = AsyncIOBackend.current_time() - self.stopping = False - - def _report_result( - self, future: asyncio.Future, result: Any, exc: BaseException | None - ) -> None: - self.idle_since = AsyncIOBackend.current_time() - if not self.stopping: - self.idle_workers.append(self) - - if not future.cancelled(): - if exc is not None: - if isinstance(exc, StopIteration): - new_exc = RuntimeError("coroutine raised StopIteration") - new_exc.__cause__ = exc - exc = new_exc - - future.set_exception(exc) - else: - future.set_result(result) - - def run(self) -> None: - with claim_worker_thread(AsyncIOBackend, self.loop): - while True: - item = self.queue.get() - if item is None: - # Shutdown command received - return - - context, func, args, future, cancel_scope = item - if not future.cancelled(): - result = None - exception: BaseException | None = None - threadlocals.current_cancel_scope = cancel_scope - try: - result = context.run(func, *args) - except BaseException as exc: - exception = exc - finally: - del threadlocals.current_cancel_scope - - if not self.loop.is_closed(): - self.loop.call_soon_threadsafe( - self._report_result, future, result, exception - ) - - del result, exception - - self.queue.task_done() - del item, context, func, args, future, cancel_scope - - def stop(self, f: asyncio.Task | None = None) -> None: - self.stopping = True - self.queue.put_nowait(None) - self.workers.discard(self) - try: - self.idle_workers.remove(self) - except ValueError: - pass - - -_threadpool_idle_workers: RunVar[deque[WorkerThread]] = RunVar( - "_threadpool_idle_workers" -) -_threadpool_workers: RunVar[set[WorkerThread]] = RunVar("_threadpool_workers") - - -# -# Subprocesses -# - - -@dataclass(eq=False) -class StreamReaderWrapper(abc.ByteReceiveStream): - _stream: asyncio.StreamReader - - async def receive(self, max_bytes: int = 65536) -> bytes: - data = await self._stream.read(max_bytes) - if data: - return data - else: - raise EndOfStream - - async def aclose(self) -> None: - self._stream.set_exception(ClosedResourceError()) - await AsyncIOBackend.checkpoint() - - -@dataclass(eq=False) -class StreamWriterWrapper(abc.ByteSendStream): - _stream: asyncio.StreamWriter - _closed: bool = field(init=False, default=False) - - async def send(self, item: bytes) -> None: - await AsyncIOBackend.checkpoint_if_cancelled() - stream_paused = self._stream._protocol._paused # type: ignore[attr-defined] - try: - self._stream.write(item) - await self._stream.drain() - except (ConnectionResetError, BrokenPipeError, RuntimeError) as exc: - # If closed by us and/or the peer: - # * on stdlib, drain() raises ConnectionResetError or BrokenPipeError - # * on uvloop and Winloop, write() eventually starts raising RuntimeError - if self._closed: - raise ClosedResourceError from exc - elif self._stream.is_closing(): - raise BrokenResourceError from exc - - raise - - if not stream_paused: - await AsyncIOBackend.cancel_shielded_checkpoint() - - async def aclose(self) -> None: - self._closed = True - self._stream.close() - await AsyncIOBackend.checkpoint() - - -@dataclass(eq=False) -class Process(abc.Process): - _process: asyncio.subprocess.Process - _stdin: StreamWriterWrapper | None - _stdout: StreamReaderWrapper | None - _stderr: StreamReaderWrapper | None - - async def aclose(self) -> None: - with CancelScope(shield=True) as scope: - if self._stdin: - await self._stdin.aclose() - if self._stdout: - await self._stdout.aclose() - if self._stderr: - await self._stderr.aclose() - - scope.shield = False - try: - await self.wait() - except BaseException: - scope.shield = True - self.kill() - await self.wait() - raise - - async def wait(self) -> int: - return await self._process.wait() - - def terminate(self) -> None: - self._process.terminate() - - def kill(self) -> None: - self._process.kill() - - def send_signal(self, signal: int) -> None: - self._process.send_signal(signal) - - @property - def pid(self) -> int: - return self._process.pid - - @property - def returncode(self) -> int | None: - return self._process.returncode - - @property - def stdin(self) -> abc.ByteSendStream | None: - return self._stdin - - @property - def stdout(self) -> abc.ByteReceiveStream | None: - return self._stdout - - @property - def stderr(self) -> abc.ByteReceiveStream | None: - return self._stderr - - -def _forcibly_shutdown_process_pool_on_exit( - workers: set[Process], _task: object -) -> None: - """ - Forcibly shuts down worker processes belonging to this event loop.""" - child_watcher: asyncio.AbstractChildWatcher | None = None # type: ignore[name-defined] - if sys.version_info < (3, 12): - try: - child_watcher = asyncio.get_event_loop_policy().get_child_watcher() - except NotImplementedError: - pass - - # Close as much as possible (w/o async/await) to avoid warnings - for process in workers.copy(): - if process.returncode is not None: - continue - - process._stdin._stream._transport.close() # type: ignore[union-attr] - process._stdout._stream._transport.close() # type: ignore[union-attr] - process._stderr._stream._transport.close() # type: ignore[union-attr] - process.kill() - if child_watcher: - child_watcher.remove_child_handler(process.pid) - - -async def _shutdown_process_pool_on_exit(workers: set[abc.Process]) -> None: - """ - Shuts down worker processes belonging to this event loop. - - NOTE: this only works when the event loop was started using asyncio.run() or - anyio.run(). - - """ - process: abc.Process - try: - await sleep(math.inf) - except asyncio.CancelledError: - workers = workers.copy() - for process in workers: - if process.returncode is None: - process.kill() - - for process in workers: - await process.aclose() - - -# -# Sockets and networking -# - - -class StreamProtocol(asyncio.Protocol): - read_queue: deque[bytes] - read_event: asyncio.Event - write_event: asyncio.Event - exception: Exception | None = None - is_at_eof: bool = False - - def connection_made(self, transport: asyncio.BaseTransport) -> None: - self.read_queue = deque() - self.read_event = asyncio.Event() - self.write_event = asyncio.Event() - self.write_event.set() - cast(asyncio.Transport, transport).set_write_buffer_limits(0) - - def connection_lost(self, exc: Exception | None) -> None: - if exc: - self.exception = exc - - self.read_event.set() - self.write_event.set() - - def data_received(self, data: bytes) -> None: - # ProactorEventloop sometimes sends bytearray instead of bytes - self.read_queue.append(bytes(data)) - self.read_event.set() - - def eof_received(self) -> bool | None: - self.is_at_eof = True - self.read_event.set() - return True - - def pause_writing(self) -> None: - self.write_event = asyncio.Event() - - def resume_writing(self) -> None: - self.write_event.set() - - -class DatagramProtocol(asyncio.DatagramProtocol): - read_queue: deque[tuple[bytes, IPSockAddrType]] - read_event: asyncio.Event - write_event: asyncio.Event - closed_event: asyncio.Event - exception: Exception | None = None - - def connection_made(self, transport: asyncio.BaseTransport) -> None: - self.read_queue = deque(maxlen=100) # arbitrary value - self.read_event = asyncio.Event() - self.write_event = asyncio.Event() - self.closed_event = asyncio.Event() - self.write_event.set() - - def connection_lost(self, exc: Exception | None) -> None: - self.read_event.set() - self.write_event.set() - self.closed_event.set() - - def datagram_received(self, data: bytes, addr: IPSockAddrType) -> None: - addr = convert_ipv6_sockaddr(addr) - self.read_queue.append((data, addr)) - self.read_event.set() - - def error_received(self, exc: Exception) -> None: - self.exception = exc - - def pause_writing(self) -> None: - self.write_event.clear() - - def resume_writing(self) -> None: - self.write_event.set() - - -class SocketStream(abc.SocketStream): - def __init__(self, transport: asyncio.Transport, protocol: StreamProtocol): - self._transport = transport - self._protocol = protocol - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - self._closed = False - - @property - def _raw_socket(self) -> socket.socket: - return self._transport.get_extra_info("socket") - - async def receive(self, max_bytes: int = 65536) -> bytes: - with self._receive_guard: - if ( - not self._protocol.read_event.is_set() - and not self._transport.is_closing() - and not self._protocol.is_at_eof - ): - self._transport.resume_reading() - await self._protocol.read_event.wait() - self._transport.pause_reading() - else: - await AsyncIOBackend.checkpoint() - - try: - chunk = self._protocol.read_queue.popleft() - except IndexError: - if self._closed: - raise ClosedResourceError from None - elif self._protocol.exception: - raise BrokenResourceError from self._protocol.exception - else: - raise EndOfStream from None - - if len(chunk) > max_bytes: - # Split the oversized chunk - chunk, leftover = chunk[:max_bytes], chunk[max_bytes:] - self._protocol.read_queue.appendleft(leftover) - - # If the read queue is empty, clear the flag so that the next call will - # block until data is available - if not self._protocol.read_queue: - self._protocol.read_event.clear() - - return chunk - - async def send(self, item: bytes) -> None: - with self._send_guard: - await AsyncIOBackend.checkpoint() - - if self._closed: - raise ClosedResourceError - elif self._protocol.exception is not None: - raise BrokenResourceError from self._protocol.exception - - try: - self._transport.write(item) - except RuntimeError as exc: - if self._transport.is_closing(): - raise BrokenResourceError from exc - else: - raise - - await self._protocol.write_event.wait() - - async def send_eof(self) -> None: - try: - self._transport.write_eof() - except OSError: - pass - - async def aclose(self) -> None: - self._closed = True - if not self._transport.is_closing(): - try: - self._transport.write_eof() - except OSError: - pass - - self._transport.close() - await sleep(0) - self._transport.abort() - - -class _RawSocketMixin: - _receive_future: asyncio.Future | None = None - _send_future: asyncio.Future | None = None - _closing = False - - def __init__(self, raw_socket: socket.socket): - self.__raw_socket = raw_socket - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - - @property - def _raw_socket(self) -> socket.socket: - return self.__raw_socket - - def _wait_until_readable(self, loop: asyncio.AbstractEventLoop) -> asyncio.Future: - def callback(f: object) -> None: - del self._receive_future - loop.remove_reader(self.__raw_socket) - - f = self._receive_future = asyncio.Future() - loop.add_reader(self.__raw_socket, f.set_result, None) - f.add_done_callback(callback) - return f - - def _wait_until_writable(self, loop: asyncio.AbstractEventLoop) -> asyncio.Future: - def callback(f: object) -> None: - del self._send_future - loop.remove_writer(self.__raw_socket) - - f = self._send_future = asyncio.Future() - loop.add_writer(self.__raw_socket, f.set_result, None) - f.add_done_callback(callback) - return f - - async def aclose(self) -> None: - if not self._closing: - self._closing = True - if self.__raw_socket.fileno() != -1: - self.__raw_socket.close() - - if self._receive_future: - self._receive_future.set_result(None) - if self._send_future: - self._send_future.set_result(None) - - -class UNIXSocketStream(_RawSocketMixin, abc.UNIXSocketStream): - async def send_eof(self) -> None: - with self._send_guard: - self._raw_socket.shutdown(socket.SHUT_WR) - - async def receive(self, max_bytes: int = 65536) -> bytes: - loop = get_running_loop() - await AsyncIOBackend.checkpoint() - with self._receive_guard: - while True: - try: - data = self._raw_socket.recv(max_bytes) - except BlockingIOError: - await self._wait_until_readable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - if not data: - raise EndOfStream - - return data - - async def send(self, item: bytes) -> None: - loop = get_running_loop() - await AsyncIOBackend.checkpoint() - with self._send_guard: - view = memoryview(item) - while view: - try: - bytes_sent = self._raw_socket.send(view) - except BlockingIOError: - await self._wait_until_writable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - view = view[bytes_sent:] - - async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]: - if not isinstance(msglen, int) or msglen < 0: - raise ValueError("msglen must be a non-negative integer") - if not isinstance(maxfds, int) or maxfds < 1: - raise ValueError("maxfds must be a positive integer") - - loop = get_running_loop() - fds = array.array("i") - await AsyncIOBackend.checkpoint() - with self._receive_guard: - while True: - try: - message, ancdata, flags, addr = self._raw_socket.recvmsg( - msglen, socket.CMSG_LEN(maxfds * fds.itemsize) - ) - except BlockingIOError: - await self._wait_until_readable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - if not message and not ancdata: - raise EndOfStream - - break - - for cmsg_level, cmsg_type, cmsg_data in ancdata: - if cmsg_level != socket.SOL_SOCKET or cmsg_type != socket.SCM_RIGHTS: - raise RuntimeError( - f"Received unexpected ancillary data; message = {message!r}, " - f"cmsg_level = {cmsg_level}, cmsg_type = {cmsg_type}" - ) - - fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) - - return message, list(fds) - - async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None: - if not message: - raise ValueError("message must not be empty") - if not fds: - raise ValueError("fds must not be empty") - - loop = get_running_loop() - filenos: list[int] = [] - for fd in fds: - if isinstance(fd, int): - filenos.append(fd) - elif isinstance(fd, IOBase): - filenos.append(fd.fileno()) - - fdarray = array.array("i", filenos) - await AsyncIOBackend.checkpoint() - with self._send_guard: - while True: - try: - # The ignore can be removed after mypy picks up - # https://github.com/python/typeshed/pull/5545 - self._raw_socket.sendmsg( - [message], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, fdarray)] - ) - break - except BlockingIOError: - await self._wait_until_writable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - - -class TCPSocketListener(abc.SocketListener): - _accept_scope: CancelScope | None = None - _closed = False - - def __init__(self, raw_socket: socket.socket): - self.__raw_socket = raw_socket - self._loop = cast(asyncio.BaseEventLoop, get_running_loop()) - self._accept_guard = ResourceGuard("accepting connections from") - - @property - def _raw_socket(self) -> socket.socket: - return self.__raw_socket - - async def accept(self) -> abc.SocketStream: - if self._closed: - raise ClosedResourceError - - with self._accept_guard: - await AsyncIOBackend.checkpoint() - with CancelScope() as self._accept_scope: - try: - client_sock, _addr = await self._loop.sock_accept(self._raw_socket) - except asyncio.CancelledError: - # Workaround for https://bugs.python.org/issue41317 - try: - self._loop.remove_reader(self._raw_socket) - except (ValueError, NotImplementedError): - pass - - if self._closed: - raise ClosedResourceError from None - - raise - finally: - self._accept_scope = None - - client_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - transport, protocol = await self._loop.connect_accepted_socket( - StreamProtocol, client_sock - ) - return SocketStream(transport, protocol) - - async def aclose(self) -> None: - if self._closed: - return - - self._closed = True - if self._accept_scope: - # Workaround for https://bugs.python.org/issue41317 - try: - self._loop.remove_reader(self._raw_socket) - except (ValueError, NotImplementedError): - pass - - self._accept_scope.cancel() - await sleep(0) - - self._raw_socket.close() - - -class UNIXSocketListener(abc.SocketListener): - def __init__(self, raw_socket: socket.socket): - self.__raw_socket = raw_socket - self._loop = get_running_loop() - self._accept_guard = ResourceGuard("accepting connections from") - self._closed = False - - async def accept(self) -> abc.SocketStream: - await AsyncIOBackend.checkpoint() - with self._accept_guard: - while True: - try: - client_sock, _ = self.__raw_socket.accept() - client_sock.setblocking(False) - return UNIXSocketStream(client_sock) - except BlockingIOError: - f: asyncio.Future = asyncio.Future() - self._loop.add_reader(self.__raw_socket, f.set_result, None) - f.add_done_callback( - lambda _: self._loop.remove_reader(self.__raw_socket) - ) - await f - except OSError as exc: - if self._closed: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - - async def aclose(self) -> None: - self._closed = True - self.__raw_socket.close() - - @property - def _raw_socket(self) -> socket.socket: - return self.__raw_socket - - -class UDPSocket(abc.UDPSocket): - def __init__( - self, transport: asyncio.DatagramTransport, protocol: DatagramProtocol - ): - self._transport = transport - self._protocol = protocol - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - self._closed = False - - @property - def _raw_socket(self) -> socket.socket: - return self._transport.get_extra_info("socket") - - async def aclose(self) -> None: - self._closed = True - if not self._transport.is_closing(): - self._transport.close() - - await self._protocol.closed_event.wait() - - async def receive(self) -> tuple[bytes, IPSockAddrType]: - with self._receive_guard: - await AsyncIOBackend.checkpoint() - - # If the buffer is empty, ask for more data - if not self._protocol.read_queue and not self._transport.is_closing(): - self._protocol.read_event.clear() - await self._protocol.read_event.wait() - - try: - return self._protocol.read_queue.popleft() - except IndexError: - if self._closed: - raise ClosedResourceError from None - else: - raise BrokenResourceError from None - - async def send(self, item: UDPPacketType) -> None: - with self._send_guard: - await AsyncIOBackend.checkpoint() - await self._protocol.write_event.wait() - if self._closed: - raise ClosedResourceError - elif self._transport.is_closing(): - raise BrokenResourceError - else: - self._transport.sendto(*item) - - -class ConnectedUDPSocket(abc.ConnectedUDPSocket): - def __init__( - self, transport: asyncio.DatagramTransport, protocol: DatagramProtocol - ): - self._transport = transport - self._protocol = protocol - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - self._closed = False - - @property - def _raw_socket(self) -> socket.socket: - return self._transport.get_extra_info("socket") - - async def aclose(self) -> None: - self._closed = True - if not self._transport.is_closing(): - self._transport.close() - - await self._protocol.closed_event.wait() - - async def receive(self) -> bytes: - with self._receive_guard: - await AsyncIOBackend.checkpoint() - - # If the buffer is empty, ask for more data - if not self._protocol.read_queue and not self._transport.is_closing(): - self._protocol.read_event.clear() - await self._protocol.read_event.wait() - - try: - packet = self._protocol.read_queue.popleft() - except IndexError: - if self._closed: - raise ClosedResourceError from None - else: - raise BrokenResourceError from None - - return packet[0] - - async def send(self, item: bytes) -> None: - with self._send_guard: - await AsyncIOBackend.checkpoint() - await self._protocol.write_event.wait() - if self._closed: - raise ClosedResourceError - elif self._transport.is_closing(): - raise BrokenResourceError - else: - self._transport.sendto(item) - - -class UNIXDatagramSocket(_RawSocketMixin, abc.UNIXDatagramSocket): - async def receive(self) -> UNIXDatagramPacketType: - loop = get_running_loop() - await AsyncIOBackend.checkpoint() - with self._receive_guard: - while True: - try: - data = self._raw_socket.recvfrom(65536) - except BlockingIOError: - await self._wait_until_readable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - return data - - async def send(self, item: UNIXDatagramPacketType) -> None: - loop = get_running_loop() - await AsyncIOBackend.checkpoint() - with self._send_guard: - while True: - try: - self._raw_socket.sendto(*item) - except BlockingIOError: - await self._wait_until_writable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - return - - -class ConnectedUNIXDatagramSocket(_RawSocketMixin, abc.ConnectedUNIXDatagramSocket): - async def receive(self) -> bytes: - loop = get_running_loop() - await AsyncIOBackend.checkpoint() - with self._receive_guard: - while True: - try: - data = self._raw_socket.recv(65536) - except BlockingIOError: - await self._wait_until_readable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - return data - - async def send(self, item: bytes) -> None: - loop = get_running_loop() - await AsyncIOBackend.checkpoint() - with self._send_guard: - while True: - try: - self._raw_socket.send(item) - except BlockingIOError: - await self._wait_until_writable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - return - - -_read_events: RunVar[dict[int, asyncio.Future[bool]]] = RunVar("read_events") -_write_events: RunVar[dict[int, asyncio.Future[bool]]] = RunVar("write_events") - - -# -# Synchronization -# - - -class Event(BaseEvent): - __slots__ = ("_event",) - - def __new__(cls) -> Event: - return object.__new__(cls) - - def __init__(self) -> None: - self._event = asyncio.Event() - - def set(self) -> None: - self._event.set() - - def is_set(self) -> bool: - return self._event.is_set() - - async def wait(self) -> None: - if self.is_set(): - await AsyncIOBackend.checkpoint() - else: - await self._event.wait() - - def statistics(self) -> EventStatistics: - return EventStatistics(len(self._event._waiters)) - - -class Lock(BaseLock): - __slots__ = "_fast_acquire", "_owner_task", "_waiters" - - def __new__(cls, *, fast_acquire: bool = False) -> Lock: - return object.__new__(cls) - - def __init__(self, *, fast_acquire: bool = False) -> None: - self._fast_acquire = fast_acquire - self._owner_task: asyncio.Task | None = None - self._waiters: deque[tuple[asyncio.Task, asyncio.Future]] = deque() - - async def acquire(self) -> None: - task = cast(asyncio.Task, current_task()) - if self._owner_task is None and not self._waiters: - await AsyncIOBackend.checkpoint_if_cancelled() - self._owner_task = task - - # Unless on the "fast path", yield control of the event loop so that other - # tasks can run too - if not self._fast_acquire: - try: - await AsyncIOBackend.cancel_shielded_checkpoint() - except CancelledError: - self.release() - raise - - return - - if self._owner_task == task: - raise RuntimeError("Attempted to acquire an already held Lock") - - fut: asyncio.Future[None] = asyncio.Future() - item = task, fut - self._waiters.append(item) - try: - await fut - except CancelledError: - if fut.cancelled(): - try: - self._waiters.remove(item) - except ValueError: - pass - else: - self.release() - - raise - - def acquire_nowait(self) -> None: - task = cast(asyncio.Task, current_task()) - if self._owner_task is None and not self._waiters: - self._owner_task = task - return - - if self._owner_task is task: - raise RuntimeError("Attempted to acquire an already held Lock") - - raise WouldBlock - - def locked(self) -> bool: - return self._owner_task is not None - - def release(self) -> None: - if self._owner_task != current_task(): - raise RuntimeError("The current task is not holding this lock") - - # A cancelled waiter that already received ownership removes itself from - # _waiters before calling release(); any cancelled waiter still queued here - # was cancelled before being woken, so drop it. - while self._waiters: - task, fut = self._waiters.popleft() - if fut.cancelled(): - continue - - self._owner_task = task - fut.set_result(None) - return - - self._owner_task = None - - def statistics(self) -> LockStatistics: - task_info = AsyncIOTaskInfo(self._owner_task) if self._owner_task else None - return LockStatistics(self.locked(), task_info, len(self._waiters)) - - -class Semaphore(BaseSemaphore): - __slots__ = "_value", "_max_value", "_fast_acquire", "_waiters" - - def __new__( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> Semaphore: - return object.__new__(cls) - - def __init__( - self, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ): - super().__init__(initial_value, max_value=max_value) - self._value = initial_value - self._max_value = max_value - self._fast_acquire = fast_acquire - self._waiters: deque[asyncio.Future[None]] = deque() - - async def acquire(self) -> None: - if self._value > 0 and not self._waiters: - await AsyncIOBackend.checkpoint_if_cancelled() - self._value -= 1 - - # Unless on the "fast path", yield control of the event loop so that other - # tasks can run too - if not self._fast_acquire: - try: - await AsyncIOBackend.cancel_shielded_checkpoint() - except CancelledError: - self.release() - raise - - return - - fut: asyncio.Future[None] = asyncio.Future() - self._waiters.append(fut) - try: - await fut - except CancelledError: - if fut.cancelled(): - try: - self._waiters.remove(fut) - except ValueError: - pass - else: - self.release() - - raise - - def acquire_nowait(self) -> None: - if self._value == 0: - raise WouldBlock - - self._value -= 1 - - def release(self) -> None: - if self._max_value is not None and self._value == self._max_value: - raise ValueError("semaphore released too many times") - - while self._waiters: - fut = self._waiters.popleft() - if fut.cancelled(): - continue - - fut.set_result(None) - return - - self._value += 1 - - @property - def value(self) -> int: - return self._value - - @property - def max_value(self) -> int | None: - return self._max_value - - def statistics(self) -> SemaphoreStatistics: - return SemaphoreStatistics(len(self._waiters)) - - -class CapacityLimiter(BaseCapacityLimiter): - __slots__ = "_total_tokens", "_borrowers", "_wait_queue" - - def __new__(cls, total_tokens: float) -> CapacityLimiter: - return object.__new__(cls) - - def __init__(self, total_tokens: float): - self._total_tokens: float = 0 - self._borrowers: set[Any] = set() - self._wait_queue: OrderedDict[Any, asyncio.Event] = OrderedDict() - self.total_tokens = total_tokens - - async def __aenter__(self) -> None: - await self.acquire() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.release() - - @property - def total_tokens(self) -> float: - return self._total_tokens - - @total_tokens.setter - def total_tokens(self, value: float) -> None: - if not isinstance(value, int) and not math.isinf(value): - raise TypeError("total_tokens must be an int or math.inf") - - if value < 0: - raise ValueError("total_tokens must be >= 0") - - waiters_to_notify = max(value - self._total_tokens, 0) - self._total_tokens = value - - # Notify waiting tasks that they have acquired the limiter - while self._wait_queue and waiters_to_notify: - event = self._wait_queue.popitem(last=False)[1] - event.set() - waiters_to_notify -= 1 - - @property - def borrowed_tokens(self) -> int: - return len(self._borrowers) - - @property - def available_tokens(self) -> float: - return self._total_tokens - len(self._borrowers) - - def _notify_next_waiter(self) -> None: - """Notify the next task in line if this limiter has free capacity now.""" - if self._wait_queue and len(self._borrowers) < self._total_tokens: - event = self._wait_queue.popitem(last=False)[1] - event.set() - - def acquire_nowait(self) -> None: - self.acquire_on_behalf_of_nowait(current_task()) - - def acquire_on_behalf_of_nowait(self, borrower: object) -> None: - if borrower in self._borrowers: - raise RuntimeError( - "this borrower is already holding one of this CapacityLimiter's tokens" - ) - - if self._wait_queue or len(self._borrowers) >= self._total_tokens: - raise WouldBlock - - self._borrowers.add(borrower) - - async def acquire(self) -> None: - return await self.acquire_on_behalf_of(current_task()) - - async def acquire_on_behalf_of(self, borrower: object) -> None: - await AsyncIOBackend.checkpoint_if_cancelled() - try: - self.acquire_on_behalf_of_nowait(borrower) - except WouldBlock: - event = asyncio.Event() - self._wait_queue[borrower] = event - try: - await event.wait() - except BaseException: - self._wait_queue.pop(borrower, None) - if event.is_set(): - self._notify_next_waiter() - - raise - - self._borrowers.add(borrower) - else: - try: - await AsyncIOBackend.cancel_shielded_checkpoint() - except BaseException: - self.release() - raise - - def release(self) -> None: - self.release_on_behalf_of(current_task()) - - def release_on_behalf_of(self, borrower: object) -> None: - try: - self._borrowers.remove(borrower) - except KeyError: - raise RuntimeError( - "this borrower isn't holding any of this CapacityLimiter's tokens" - ) from None - - self._notify_next_waiter() - - def statistics(self) -> CapacityLimiterStatistics: - return CapacityLimiterStatistics( - self.borrowed_tokens, - self.total_tokens, - tuple(self._borrowers), - len(self._wait_queue), - ) - - -_default_thread_limiter: RunVar[CapacityLimiter] = RunVar("_default_thread_limiter") - - -# -# Operating system signals -# - - -class _SignalReceiver: - def __init__(self, signals: tuple[Signals, ...]): - self._signals = signals - self._loop = get_running_loop() - self._signal_queue: deque[Signals] = deque() - self._future: asyncio.Future = asyncio.Future() - self._handled_signals: set[Signals] = set() - - def _deliver(self, signum: Signals) -> None: - self._signal_queue.append(signum) - if not self._future.done(): - self._future.set_result(None) - - def __enter__(self) -> _SignalReceiver: - for sig in set(self._signals): - self._loop.add_signal_handler(sig, self._deliver, sig) - self._handled_signals.add(sig) - - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - for sig in self._handled_signals: - self._loop.remove_signal_handler(sig) - - def __aiter__(self) -> _SignalReceiver: - return self - - async def __anext__(self) -> Signals: - await AsyncIOBackend.checkpoint() - if not self._signal_queue: - self._future = asyncio.Future() - await self._future - - return self._signal_queue.popleft() - - -# -# Testing and debugging -# - - -class AsyncIOTaskInfo(TaskInfo): - def __init__(self, task: asyncio.Task): - task_state = _task_states.get(task) - if task_state is None: - parent_id = None - else: - parent_id = task_state.parent_id - - coro = task.get_coro() - assert coro is not None, "created TaskInfo from a completed Task" - super().__init__(id(task), parent_id, task.get_name(), coro) - self._task = weakref.ref(task) - - def has_pending_cancellation(self) -> bool: - if not (task := self._task()): - # If the task isn't around anymore, it won't have a pending cancellation - return False - - if task._must_cancel: # type: ignore[attr-defined] - return True - elif ( - isinstance(task._fut_waiter, asyncio.Future) # type: ignore[attr-defined] - and task._fut_waiter.cancelled() # type: ignore[attr-defined] - ): - return True - - if task_state := _task_states.get(task): - if cancel_scope := task_state.cancel_scope: - return cancel_scope._effectively_cancelled - - return False - - -class TestRunner(abc.TestRunner): - _send_stream: MemoryObjectSendStream[tuple[Awaitable[Any], asyncio.Future[Any]]] - - def __init__( - self, - *, - debug: bool | None = None, - use_uvloop: bool = False, - loop_factory: Callable[[], AbstractEventLoop] | None = None, - ) -> None: - if use_uvloop and loop_factory is None: - if sys.platform != "win32": - import uvloop - - loop_factory = uvloop.new_event_loop - else: - import winloop - - loop_factory = winloop.new_event_loop - - self._runner = Runner(debug=debug, loop_factory=loop_factory) - self._exceptions: list[BaseException] = [] - self._runner_task: asyncio.Task | None = None - - def __enter__(self) -> TestRunner: - self._runner.__enter__() - self.get_loop().set_exception_handler(self._exception_handler) - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self._runner.__exit__(exc_type, exc_val, exc_tb) - - def get_loop(self) -> AbstractEventLoop: - return self._runner.get_loop() - - def is_running(self) -> bool: - try: - asyncio.get_running_loop() - return True - except RuntimeError: - return False - - def _exception_handler( - self, loop: asyncio.AbstractEventLoop, context: dict[str, Any] - ) -> None: - if isinstance(context.get("exception"), Exception): - self._exceptions.append(context["exception"]) - else: - loop.default_exception_handler(context) - - def _raise_async_exceptions(self) -> None: - # Re-raise any exceptions raised in asynchronous callbacks - if self._exceptions: - exceptions, self._exceptions = self._exceptions, [] - if len(exceptions) == 1: - raise exceptions[0] - elif exceptions: - raise BaseExceptionGroup( - "Multiple exceptions occurred in asynchronous callbacks", exceptions - ) - - async def _run_tests_and_fixtures( - self, - receive_stream: MemoryObjectReceiveStream[ - tuple[Awaitable[T_Retval], asyncio.Future[T_Retval]] - ], - ) -> None: - from _pytest.outcomes import OutcomeException - - with receive_stream, self._send_stream: - async for coro, future in receive_stream: - try: - retval = await coro - except CancelledError as exc: - if not future.cancelled(): - future.cancel(*exc.args) - - raise - except BaseException as exc: - if not future.cancelled(): - future.set_exception(exc) - - if not isinstance(exc, (Exception, OutcomeException)): - raise - else: - if not future.cancelled(): - future.set_result(retval) - - async def _call_in_runner_task( - self, - func: Callable[P, Awaitable[T_Retval]], - /, - *args: P.args, - **kwargs: P.kwargs, - ) -> T_Retval: - if not self._runner_task: - self._send_stream, receive_stream = create_memory_object_stream[ - tuple[Awaitable[Any], asyncio.Future] - ](1) - self._runner_task = self.get_loop().create_task( - self._run_tests_and_fixtures(receive_stream) - ) - - coro = func(*args, **kwargs) - future: asyncio.Future[T_Retval] = self.get_loop().create_future() - self._send_stream.send_nowait((coro, future)) - return await future - - def run_asyncgen_fixture( - self, - fixture_func: Callable[..., AsyncGenerator[T_Retval, Any]], - kwargs: dict[str, Any], - ) -> Iterable[T_Retval]: - asyncgen = fixture_func(**kwargs) - fixturevalue: T_Retval = self.get_loop().run_until_complete( - self._call_in_runner_task(asyncgen.asend, None) - ) - self._raise_async_exceptions() - - yield fixturevalue - - try: - self.get_loop().run_until_complete( - self._call_in_runner_task(asyncgen.asend, None) - ) - except StopAsyncIteration: - self._raise_async_exceptions() - else: - self.get_loop().run_until_complete(asyncgen.aclose()) - raise RuntimeError("Async generator fixture did not stop") - - def run_fixture( - self, - fixture_func: Callable[..., Coroutine[Any, Any, T_Retval]], - kwargs: dict[str, Any], - ) -> T_Retval: - retval = self.get_loop().run_until_complete( - self._call_in_runner_task(fixture_func, **kwargs) - ) - self._raise_async_exceptions() - return retval - - def run_test( - self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any] - ) -> None: - try: - self.get_loop().run_until_complete( - self._call_in_runner_task(test_func, **kwargs) - ) - except Exception as exc: - self._exceptions.append(exc) - except BaseException: - # A BaseException (e.g. KeyboardInterrupt, SystemExit) interrupted the event loop before - # the test completed. Cancel _runner_task so it does not resume when the event - # loop is re-entered during async generator fixture teardown. - if self._runner_task is not None and not self._runner_task.done(): - self._runner_task.cancel() - self._send_stream.close() - try: - self.get_loop().run_until_complete(self._runner_task) - except CancelledError: - pass - finally: - self._runner_task = None - raise - self._raise_async_exceptions() - - -class AsyncIOBackend(AsyncBackend): - @classmethod - def run( - cls, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - args: tuple[Unpack[PosArgsT]], - kwargs: dict[str, Any], - options: dict[str, Any], - ) -> T_Retval: - @wraps(func) - async def wrapper() -> T_Retval: - task = cast(asyncio.Task, current_task()) - task.set_name(get_callable_name(func)) - _task_states[task] = TaskState(None, None) - - try: - return await func(*args) - finally: - del _task_states[task] - - debug = options.get("debug", None) - loop_factory = options.get("loop_factory", None) - if loop_factory is None and options.get("use_uvloop", False): - if sys.platform != "win32": - import uvloop - - loop_factory = uvloop.new_event_loop - else: - import winloop - - loop_factory = winloop.new_event_loop - - with Runner(debug=debug, loop_factory=loop_factory) as runner: - return runner.run(wrapper()) - - @classmethod - def current_token(cls) -> object: - return get_running_loop() - - @classmethod - def current_time(cls) -> float: - return get_running_loop().time() - - @classmethod - def cancelled_exception_class(cls) -> type[BaseException]: - return CancelledError - - @classmethod - async def checkpoint(cls) -> None: - await sleep(0) - - @classmethod - async def checkpoint_if_cancelled(cls) -> None: - task = current_task() - if task is None: - return - - try: - cancel_scope = _task_states[task].cancel_scope - except KeyError: - return - - while cancel_scope: - if cancel_scope.cancel_called: - await sleep(0) - elif cancel_scope.shield: - break - else: - cancel_scope = cancel_scope._parent_scope - - @classmethod - async def cancel_shielded_checkpoint(cls) -> None: - with CancelScope(shield=True): - await sleep(0) - - @classmethod - async def sleep(cls, delay: float) -> None: - await sleep(delay) - - @classmethod - def create_cancel_scope( - cls, *, deadline: float = math.inf, shield: bool = False - ) -> CancelScope: - return CancelScope(deadline=deadline, shield=shield) - - @classmethod - def current_effective_deadline(cls) -> float: - if (task := current_task()) is None: - return math.inf - - try: - cancel_scope = _task_states[task].cancel_scope - except KeyError: - return math.inf - - deadline = math.inf - while cancel_scope: - deadline = min(deadline, cancel_scope.deadline) - if cancel_scope._cancel_called: - deadline = -math.inf - break - elif cancel_scope.shield: - break - else: - cancel_scope = cancel_scope._parent_scope - - return deadline - - @classmethod - def create_task_group(cls) -> abc.TaskGroup: - return TaskGroup() - - @classmethod - def create_event(cls) -> abc.Event: - return Event() - - @classmethod - def create_lock(cls, *, fast_acquire: bool) -> abc.Lock: - return Lock(fast_acquire=fast_acquire) - - @classmethod - def create_semaphore( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> abc.Semaphore: - return Semaphore(initial_value, max_value=max_value, fast_acquire=fast_acquire) - - @classmethod - def create_capacity_limiter(cls, total_tokens: float) -> abc.CapacityLimiter: - return CapacityLimiter(total_tokens) - - @classmethod - async def run_sync_in_worker_thread( # type: ignore[return] - cls, - func: Callable[[Unpack[PosArgsT]], T_Retval], - args: tuple[Unpack[PosArgsT]], - abandon_on_cancel: bool = False, - limiter: abc.CapacityLimiter | None = None, - ) -> T_Retval: - await cls.checkpoint() - - # If this is the first run in this event loop thread, set up the necessary - # variables - try: - idle_workers = _threadpool_idle_workers.get() - workers = _threadpool_workers.get() - except LookupError: - idle_workers = deque() - workers = set() - _threadpool_idle_workers.set(idle_workers) - _threadpool_workers.set(workers) - - async with limiter or cls.current_default_thread_limiter(): - with CancelScope(shield=not abandon_on_cancel) as scope: - future = asyncio.Future[T_Retval]() - root_task = find_root_task() - if not idle_workers: - worker = WorkerThread(root_task, workers, idle_workers) - worker.start() - workers.add(worker) - root_task.add_done_callback( - worker.stop, context=contextvars.Context() - ) - else: - worker = idle_workers.pop() - - # Prune any other workers that have been idle for MAX_IDLE_TIME - # seconds or longer - now = cls.current_time() - while idle_workers: - if ( - now - idle_workers[0].idle_since - < WorkerThread.MAX_IDLE_TIME - ): - break - - expired_worker = idle_workers.popleft() - expired_worker.root_task.remove_done_callback( - expired_worker.stop - ) - expired_worker.stop() - - context = copy_context() - context.run(set_current_async_library, None) - if abandon_on_cancel or scope._parent_scope is None: - worker_scope = scope - else: - worker_scope = scope._parent_scope - - worker.queue.put_nowait((context, func, args, future, worker_scope)) - return await future - - @classmethod - def check_cancelled(cls) -> None: - scope: CancelScope | None = threadlocals.current_cancel_scope - while scope is not None: - if scope.cancel_called: - raise CancelledError(f"Cancelled via cancel scope {id(scope):x}") - - if scope.shield: - return - - scope = scope._parent_scope - - @classmethod - def run_async_from_thread( - cls, - func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]], - args: tuple[Unpack[PosArgsT]], - token: object, - ) -> T_co: - async def task_wrapper() -> T_co: - __tracebackhide__ = True - if scope is not None: - task = cast(asyncio.Task, current_task()) - _task_states[task] = TaskState(None, scope) - scope._tasks.add(task) - try: - return await func(*args) - except CancelledError as exc: - raise concurrent.futures.CancelledError(str(exc)) from None - finally: - if scope is not None: - scope._tasks.discard(task) - - loop = cast( - "AbstractEventLoop", token or threadlocals.current_token.native_token - ) - if loop.is_closed(): - raise RunFinishedError - - context = copy_context() - context.run(set_current_async_library, "asyncio") - scope = getattr(threadlocals, "current_cancel_scope", None) - f: concurrent.futures.Future[T_co] = context.run( - asyncio.run_coroutine_threadsafe, task_wrapper(), loop=loop - ) - return f.result() - - @classmethod - def run_sync_from_thread( - cls, - func: Callable[[Unpack[PosArgsT]], T_Retval], - args: tuple[Unpack[PosArgsT]], - token: object, - ) -> T_Retval: - @wraps(func) - def wrapper() -> None: - try: - set_current_async_library("asyncio") - f.set_result(func(*args)) - except BaseException as exc: - f.set_exception(exc) - if not isinstance(exc, Exception): - raise - - loop = cast( - "AbstractEventLoop", token or threadlocals.current_token.native_token - ) - if loop.is_closed(): - raise RunFinishedError - - f: concurrent.futures.Future[T_Retval] = Future() - loop.call_soon_threadsafe(wrapper) - return f.result() - - @classmethod - async def open_process( - cls, - command: StrOrBytesPath | Sequence[StrOrBytesPath], - *, - stdin: int | IO[Any] | None, - stdout: int | IO[Any] | None, - stderr: int | IO[Any] | None, - **kwargs: Any, - ) -> Process: - await cls.checkpoint() - if isinstance(command, PathLike): - command = os.fspath(command) - - if isinstance(command, (str, bytes)): - process = await asyncio.create_subprocess_shell( - command, - stdin=stdin, - stdout=stdout, - stderr=stderr, - **kwargs, - ) - else: - process = await asyncio.create_subprocess_exec( - *command, - stdin=stdin, - stdout=stdout, - stderr=stderr, - **kwargs, - ) - - stdin_stream = StreamWriterWrapper(process.stdin) if process.stdin else None - stdout_stream = StreamReaderWrapper(process.stdout) if process.stdout else None - stderr_stream = StreamReaderWrapper(process.stderr) if process.stderr else None - return Process(process, stdin_stream, stdout_stream, stderr_stream) - - @classmethod - def setup_process_pool_exit_at_shutdown(cls, workers: set[abc.Process]) -> None: - create_task( - _shutdown_process_pool_on_exit(workers), - name="AnyIO process pool shutdown task", - ) - find_root_task().add_done_callback( - partial(_forcibly_shutdown_process_pool_on_exit, workers) # type:ignore[arg-type] - ) - - @classmethod - async def connect_tcp( - cls, host: str, port: int, local_address: IPSockAddrType | None = None - ) -> abc.SocketStream: - transport, protocol = cast( - tuple[asyncio.Transport, StreamProtocol], - await get_running_loop().create_connection( - StreamProtocol, host, port, local_addr=local_address - ), - ) - transport.pause_reading() - return SocketStream(transport, protocol) - - @classmethod - async def connect_unix(cls, path: str | bytes) -> abc.UNIXSocketStream: - await cls.checkpoint() - loop = get_running_loop() - raw_socket = socket.socket(socket.AF_UNIX) - raw_socket.setblocking(False) - while True: - try: - raw_socket.connect(path) - except BlockingIOError: - f: asyncio.Future = asyncio.Future() - loop.add_writer(raw_socket, f.set_result, None) - f.add_done_callback(lambda _: loop.remove_writer(raw_socket)) - await f - except BaseException: - raw_socket.close() - raise - else: - return UNIXSocketStream(raw_socket) - - @classmethod - def create_tcp_listener(cls, sock: socket.socket) -> SocketListener: - return TCPSocketListener(sock) - - @classmethod - def create_unix_listener(cls, sock: socket.socket) -> SocketListener: - return UNIXSocketListener(sock) - - @classmethod - async def create_udp_socket( - cls, - family: AddressFamily, - local_address: IPSockAddrType | None, - remote_address: IPSockAddrType | None, - reuse_port: bool, - ) -> UDPSocket | ConnectedUDPSocket: - transport, protocol = await get_running_loop().create_datagram_endpoint( - DatagramProtocol, - local_addr=local_address, - remote_addr=remote_address, - family=family, - reuse_port=reuse_port, - ) - if protocol.exception: - transport.close() - raise protocol.exception - - if not remote_address: - return UDPSocket(transport, protocol) - else: - return ConnectedUDPSocket(transport, protocol) - - @classmethod - async def create_unix_datagram_socket( # type: ignore[override] - cls, raw_socket: socket.socket, remote_path: str | bytes | None - ) -> abc.UNIXDatagramSocket | abc.ConnectedUNIXDatagramSocket: - await cls.checkpoint() - loop = get_running_loop() - - if remote_path: - while True: - try: - raw_socket.connect(remote_path) - except BlockingIOError: - f: asyncio.Future = asyncio.Future() - loop.add_writer(raw_socket, f.set_result, None) - f.add_done_callback(lambda _: loop.remove_writer(raw_socket)) - await f - except BaseException: - raw_socket.close() - raise - else: - return ConnectedUNIXDatagramSocket(raw_socket) - else: - return UNIXDatagramSocket(raw_socket) - - @classmethod - async def getaddrinfo( - cls, - host: bytes | str | None, - port: str | int | None, - *, - family: int | AddressFamily = 0, - type: int | SocketKind = 0, - proto: int = 0, - flags: int = 0, - ) -> Sequence[ - tuple[ - AddressFamily, - SocketKind, - int, - str, - tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], - ] - ]: - return await get_running_loop().getaddrinfo( - host, port, family=family, type=type, proto=proto, flags=flags - ) - - @classmethod - async def getnameinfo( - cls, sockaddr: IPSockAddrType, flags: int = 0 - ) -> tuple[str, str]: - return await get_running_loop().getnameinfo(sockaddr, flags) - - @classmethod - async def wait_readable(cls, obj: FileDescriptorLike) -> None: - try: - read_events = _read_events.get() - except LookupError: - read_events = {} - _read_events.set(read_events) - - fd = obj if isinstance(obj, int) else obj.fileno() - if read_events.get(fd): - raise BusyResourceError("reading from") - - loop = get_running_loop() - fut: asyncio.Future[bool] = loop.create_future() - - def cb() -> None: - try: - del read_events[fd] - except KeyError: - pass - else: - remove_reader(fd) - - try: - fut.set_result(True) - except asyncio.InvalidStateError: - pass - - try: - loop.add_reader(fd, cb) - except NotImplementedError: - from anyio._core._asyncio_selector_thread import get_selector - - selector = get_selector() - selector.add_reader(fd, cb) - remove_reader = selector.remove_reader - else: - remove_reader = loop.remove_reader - - read_events[fd] = fut - try: - success = await fut - finally: - try: - del read_events[fd] - except KeyError: - pass - else: - remove_reader(fd) - - if not success: - raise ClosedResourceError - - @classmethod - async def wait_writable(cls, obj: FileDescriptorLike) -> None: - try: - write_events = _write_events.get() - except LookupError: - write_events = {} - _write_events.set(write_events) - - fd = obj if isinstance(obj, int) else obj.fileno() - if write_events.get(fd): - raise BusyResourceError("writing to") - - loop = get_running_loop() - fut: asyncio.Future[bool] = loop.create_future() - - def cb() -> None: - try: - del write_events[fd] - except KeyError: - pass - else: - remove_writer(fd) - - try: - fut.set_result(True) - except asyncio.InvalidStateError: - pass - - try: - loop.add_writer(fd, cb) - except NotImplementedError: - from anyio._core._asyncio_selector_thread import get_selector - - selector = get_selector() - selector.add_writer(fd, cb) - remove_writer = selector.remove_writer - else: - remove_writer = loop.remove_writer - - write_events[fd] = fut - try: - success = await fut - finally: - try: - del write_events[fd] - except KeyError: - pass - else: - remove_writer(fd) - - if not success: - raise ClosedResourceError - - @classmethod - def notify_closing(cls, obj: FileDescriptorLike) -> None: - fd = obj if isinstance(obj, int) else obj.fileno() - loop = get_running_loop() - - try: - write_events = _write_events.get() - except LookupError: - pass - else: - try: - fut = write_events.pop(fd) - except KeyError: - pass - else: - try: - fut.set_result(False) - except asyncio.InvalidStateError: - pass - - try: - loop.remove_writer(fd) - except NotImplementedError: - from anyio._core._asyncio_selector_thread import get_selector - - get_selector().remove_writer(fd) - - try: - read_events = _read_events.get() - except LookupError: - pass - else: - try: - fut = read_events.pop(fd) - except KeyError: - pass - else: - try: - fut.set_result(False) - except asyncio.InvalidStateError: - pass - - try: - loop.remove_reader(fd) - except NotImplementedError: - from anyio._core._asyncio_selector_thread import get_selector - - get_selector().remove_reader(fd) - - @classmethod - async def wrap_listener_socket(cls, sock: socket.socket) -> SocketListener: - if hasattr(socket, "AF_UNIX") and sock.family == socket.AF_UNIX: - return UNIXSocketListener(sock) - - return TCPSocketListener(sock) - - @classmethod - async def wrap_stream_socket(cls, sock: socket.socket) -> SocketStream: - transport, protocol = await get_running_loop().create_connection( - StreamProtocol, sock=sock - ) - return SocketStream(transport, protocol) - - @classmethod - async def wrap_unix_stream_socket(cls, sock: socket.socket) -> UNIXSocketStream: - return UNIXSocketStream(sock) - - @classmethod - async def wrap_udp_socket(cls, sock: socket.socket) -> UDPSocket: - transport, protocol = await get_running_loop().create_datagram_endpoint( - DatagramProtocol, sock=sock - ) - return UDPSocket(transport, protocol) - - @classmethod - async def wrap_connected_udp_socket(cls, sock: socket.socket) -> ConnectedUDPSocket: - transport, protocol = await get_running_loop().create_datagram_endpoint( - DatagramProtocol, sock=sock - ) - return ConnectedUDPSocket(transport, protocol) - - @classmethod - async def wrap_unix_datagram_socket(cls, sock: socket.socket) -> UNIXDatagramSocket: - return UNIXDatagramSocket(sock) - - @classmethod - async def wrap_connected_unix_datagram_socket( - cls, sock: socket.socket - ) -> ConnectedUNIXDatagramSocket: - return ConnectedUNIXDatagramSocket(sock) - - @classmethod - def current_default_thread_limiter(cls) -> CapacityLimiter: - try: - return _default_thread_limiter.get() - except LookupError: - limiter = CapacityLimiter(40) - _default_thread_limiter.set(limiter) - return limiter - - @classmethod - def open_signal_receiver( - cls, *signals: Signals - ) -> AbstractContextManager[AsyncIterator[Signals]]: - return _SignalReceiver(signals) - - @classmethod - def get_current_task(cls) -> TaskInfo: - return AsyncIOTaskInfo(current_task()) # type: ignore[arg-type] - - @classmethod - def get_running_tasks(cls) -> Sequence[TaskInfo]: - return [AsyncIOTaskInfo(task) for task in all_tasks() if not task.done()] - - @classmethod - async def wait_all_tasks_blocked(cls) -> None: - await cls.checkpoint() - this_task = current_task() - while True: - for task in all_tasks(): - if task is this_task: - continue - - waiter = task._fut_waiter # type: ignore[attr-defined] - if waiter is None or waiter.done(): - await sleep(0.1) - break - else: - return - - @classmethod - def create_test_runner(cls, options: dict[str, Any]) -> TestRunner: - return TestRunner(**options) - - -backend_class = AsyncIOBackend diff --git a/server/venv/Lib/site-packages/anyio/_backends/_trio.py b/server/venv/Lib/site-packages/anyio/_backends/_trio.py deleted file mode 100644 index 091c78c..0000000 --- a/server/venv/Lib/site-packages/anyio/_backends/_trio.py +++ /dev/null @@ -1,1456 +0,0 @@ -from __future__ import annotations - -import array -import math -import os -import socket -import sys -import types -import weakref -from collections.abc import ( - AsyncGenerator, - AsyncIterator, - Awaitable, - Callable, - Collection, - Coroutine, - Iterable, - Sequence, -) -from contextlib import AbstractContextManager -from contextvars import Context -from dataclasses import dataclass -from functools import partial, wraps -from io import IOBase -from os import PathLike -from signal import Signals -from socket import AddressFamily, SocketKind -from types import TracebackType -from typing import ( - IO, - TYPE_CHECKING, - Any, - Generic, - Literal, - NoReturn, - ParamSpec, - TypeVar, - cast, - overload, -) - -import trio.from_thread -import trio.lowlevel -from outcome import Error, Outcome, Value -from trio.lowlevel import ( - current_root_task, - current_task, - notify_closing, - wait_readable, - wait_writable, -) -from trio.socket import SocketType as TrioSocketType -from trio.to_thread import run_sync - -from .. import ( - CapacityLimiterStatistics, - EventStatistics, - LockStatistics, - RunFinishedError, - TaskInfo, - WouldBlock, - abc, -) -from .._core._eventloop import claim_worker_thread -from .._core._exceptions import ( - BrokenResourceError, - BusyResourceError, - ClosedResourceError, - EndOfStream, -) -from .._core._sockets import convert_ipv6_sockaddr -from .._core._streams import create_memory_object_stream -from .._core._synchronization import ( - CapacityLimiter as BaseCapacityLimiter, -) -from .._core._synchronization import Event as BaseEvent -from .._core._synchronization import Lock as BaseLock -from .._core._synchronization import ( - ResourceGuard, - SemaphoreStatistics, -) -from .._core._synchronization import Semaphore as BaseSemaphore -from .._core._tasks import CancelScope as BaseCancelScope -from .._core._tasks import TaskHandle -from ..abc import IPSockAddrType, UDPPacketType, UNIXDatagramPacketType -from ..abc._eventloop import AsyncBackend, StrOrBytesPath -from ..abc._tasks import T_contra, call_for_coroutine, get_callable_name -from ..streams.memory import MemoryObjectSendStream - -if TYPE_CHECKING: - from _typeshed import FileDescriptorLike - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from exceptiongroup import BaseExceptionGroup - from typing_extensions import TypeVarTuple, Unpack - -T = TypeVar("T") -T_Retval = TypeVar("T_Retval") -T_co = TypeVar("T_co", covariant=True) -T_SockAddr = TypeVar("T_SockAddr", str, IPSockAddrType) -PosArgsT = TypeVarTuple("PosArgsT") -P = ParamSpec("P") - - -def ensure_returns_coro( - func: Callable[P, Awaitable[T_Retval]], -) -> Callable[P, Coroutine[Any, Any, T_Retval]]: - @wraps(func) - def wrapper(*args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, T_Retval]: - awaitable = func(*args, **kwargs) - # Check the common case first. - if isinstance(awaitable, Coroutine): - return awaitable - elif not isinstance(awaitable, Awaitable): - # The user violated the type annotations. Still, we should pass this on to - # Trio so it can raise with an appropriate message. - return awaitable - else: - - @wraps(func) - async def inner_wrapper() -> T_Retval: - return await awaitable - - return inner_wrapper() - - return wrapper - - -# -# Event loop -# - -RunVar = trio.lowlevel.RunVar - - -# -# Timeouts and cancellation -# - - -class CancelScope(BaseCancelScope): - __slots__ = ("__original",) - - def __new__( - cls, original: trio.CancelScope | None = None, **kwargs: object - ) -> CancelScope: - return object.__new__(cls) - - def __init__(self, original: trio.CancelScope | None = None, **kwargs: Any) -> None: - self.__original = original or trio.CancelScope(**kwargs) - - def __enter__(self) -> CancelScope: - self.__original.__enter__() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - return self.__original.__exit__(exc_type, exc_val, exc_tb) - - def cancel(self, reason: str | None = None) -> None: - self.__original.cancel(reason) - - @property - def deadline(self) -> float: - return self.__original.deadline - - @deadline.setter - def deadline(self, value: float) -> None: - self.__original.deadline = value - - @property - def cancel_called(self) -> bool: - return self.__original.cancel_called - - @property - def cancelled_caught(self) -> bool: - return self.__original.cancelled_caught - - @property - def shield(self) -> bool: - return self.__original.shield - - @shield.setter - def shield(self, value: bool) -> None: - self.__original.shield = value - - -# -# Task groups -# - -empty_start_value = object() - - -class _TrioTaskStatus(Generic[T_contra], abc.TaskStatus[T_contra]): - early_start_value: T_contra | object = empty_start_value - real_task_status: trio.TaskStatus[T_contra | None] | None = None - - def started(self, value: T_contra | None = None) -> None: - if self.real_task_status is None: - if self.early_start_value is not empty_start_value: - raise RuntimeError("called 'started' twice on the same task status") - - self.early_start_value = value - else: - self.real_task_status.started(value) - - -class TaskGroup(abc.TaskGroup): - def __init__(self) -> None: - self._entered = False - self._active = False - self._nursery_manager = trio.open_nursery(strict_exception_groups=True) - self.cancel_scope = None # type: ignore[assignment] - - async def __aenter__(self) -> TaskGroup: - if self._entered: - raise RuntimeError("TaskGroup cannot be entered more than once") - - self._entered = True - self._active = True - self._nursery = await self._nursery_manager.__aenter__() - self.cancel_scope = CancelScope(self._nursery.cancel_scope) - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - try: - # trio.Nursery.__exit__ returns bool; .open_nursery has wrong type - return await self._nursery_manager.__aexit__(exc_type, exc_val, exc_tb) # type: ignore[return-value] - except BaseExceptionGroup as exc: - if not exc.split(trio.Cancelled)[1]: - raise trio.Cancelled._create() from exc - - raise - finally: - del exc_val, exc_tb - self._active = False - - def _check_active(self, coro: Coroutine | None = None) -> None: - if not self._active: - if coro is not None: - coro.close() - - raise RuntimeError( - "This task group is not active; no new tasks can be started." - ) - - def create_task( - self, - coro: Coroutine[Any, Any, T_co], - *, - name: object = None, - context: Context | None = None, - ) -> TaskHandle[T_co]: - if not isinstance(coro, Coroutine): - raise TypeError(f"expected a coroutine, got {coro.__class__.__qualname__}") - - self._check_active(coro) - handle = TaskHandle(coro, name) - if context is not None: - context.run( - partial(self._nursery.start_soon, handle._run_coro, name=handle.name) - ) - else: - self._nursery.start_soon(handle._run_coro, name=handle.name) - - return handle - - async def start( - self, - func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]], - *args: Unpack[PosArgsT], - name: object = None, - return_handle: Literal[False] | Literal[True] = False, - ) -> Any: - handle: TaskHandle[T_co] - - async def run_coro_with_task_status( - *, task_status: trio.TaskStatus[Any] - ) -> None: - nonlocal handle - wrapper_task_status = _TrioTaskStatus() - coro = call_for_coroutine(func, args, task_status=wrapper_task_status) - if wrapper_task_status.early_start_value is not empty_start_value: - task_status.started(wrapper_task_status.early_start_value) - else: - wrapper_task_status.real_task_status = task_status - - handle = TaskHandle(coro, name) - await handle._run_coro() - - self._check_active() - final_name = get_callable_name(func, name) - start_value = await self._nursery.start( - run_coro_with_task_status, name=final_name - ) - if return_handle: - handle._start_value = start_value - return handle - else: - return start_value - - -# -# Subprocesses -# - - -@dataclass(eq=False) -class ReceiveStreamWrapper(abc.ByteReceiveStream): - _stream: trio.abc.ReceiveStream - - async def receive(self, max_bytes: int | None = None) -> bytes: - try: - data = await self._stream.receive_some(max_bytes) - except trio.ClosedResourceError as exc: - raise ClosedResourceError from exc.__cause__ - except trio.BrokenResourceError as exc: - raise BrokenResourceError from exc.__cause__ - - if data: - return bytes(data) - else: - raise EndOfStream - - async def aclose(self) -> None: - await self._stream.aclose() - - -@dataclass(eq=False) -class SendStreamWrapper(abc.ByteSendStream): - _stream: trio.abc.SendStream - - async def send(self, item: bytes) -> None: - try: - await self._stream.send_all(item) - except trio.ClosedResourceError as exc: - raise ClosedResourceError from exc.__cause__ - except trio.BrokenResourceError as exc: - raise BrokenResourceError from exc.__cause__ - - async def aclose(self) -> None: - await self._stream.aclose() - - -@dataclass(eq=False) -class Process(abc.Process): - _process: trio.Process - _stdin: abc.ByteSendStream | None - _stdout: abc.ByteReceiveStream | None - _stderr: abc.ByteReceiveStream | None - - async def aclose(self) -> None: - with CancelScope(shield=True): - if self._stdin: - await self._stdin.aclose() - if self._stdout: - await self._stdout.aclose() - if self._stderr: - await self._stderr.aclose() - - try: - await self.wait() - except BaseException: - self.kill() - with CancelScope(shield=True): - await self.wait() - raise - - async def wait(self) -> int: - return await self._process.wait() - - def terminate(self) -> None: - self._process.terminate() - - def kill(self) -> None: - self._process.kill() - - def send_signal(self, signal: Signals) -> None: - self._process.send_signal(signal) - - @property - def pid(self) -> int: - return self._process.pid - - @property - def returncode(self) -> int | None: - return self._process.returncode - - @property - def stdin(self) -> abc.ByteSendStream | None: - return self._stdin - - @property - def stdout(self) -> abc.ByteReceiveStream | None: - return self._stdout - - @property - def stderr(self) -> abc.ByteReceiveStream | None: - return self._stderr - - -class _ProcessPoolShutdownInstrument(trio.abc.Instrument): - def after_run(self) -> None: - super().after_run() - - -current_default_worker_process_limiter: trio.lowlevel.RunVar = RunVar( - "current_default_worker_process_limiter" -) - - -async def _shutdown_process_pool(workers: set[abc.Process]) -> None: - try: - await trio.sleep(math.inf) - except trio.Cancelled: - for process in workers: - if process.returncode is None: - process.kill() - - with CancelScope(shield=True): - for process in workers: - await process.aclose() - - -# -# Sockets and networking -# - - -class _TrioSocketMixin(Generic[T_SockAddr]): - def __init__(self, trio_socket: TrioSocketType) -> None: - self._trio_socket = trio_socket - self._closed = False - - def _check_closed(self) -> None: - if self._closed: - raise ClosedResourceError - if self._trio_socket.fileno() < 0: - raise BrokenResourceError - - @property - def _raw_socket(self) -> socket.socket: - return self._trio_socket._sock # type: ignore[attr-defined] - - async def aclose(self) -> None: - if self._trio_socket.fileno() >= 0: - self._closed = True - self._trio_socket.close() - - def _convert_socket_error(self, exc: BaseException) -> NoReturn: - if isinstance(exc, trio.ClosedResourceError): - raise ClosedResourceError from exc - elif self._trio_socket.fileno() < 0 and self._closed: - raise ClosedResourceError from None - elif isinstance(exc, OSError): - raise BrokenResourceError from exc - else: - raise exc - - -class SocketStream(_TrioSocketMixin, abc.SocketStream): - def __init__(self, trio_socket: TrioSocketType) -> None: - super().__init__(trio_socket) - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - - async def receive(self, max_bytes: int = 65536) -> bytes: - with self._receive_guard: - try: - data = await self._trio_socket.recv(max_bytes) - except BaseException as exc: - self._convert_socket_error(exc) - - if data: - return data - else: - raise EndOfStream - - async def send(self, item: bytes) -> None: - with self._send_guard: - view = memoryview(item) - while view: - try: - bytes_sent = await self._trio_socket.send(view) - except BaseException as exc: - self._convert_socket_error(exc) - - view = view[bytes_sent:] - - async def send_eof(self) -> None: - self._trio_socket.shutdown(socket.SHUT_WR) - - -class UNIXSocketStream(SocketStream, abc.UNIXSocketStream): - async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]: - if not isinstance(msglen, int) or msglen < 0: - raise ValueError("msglen must be a non-negative integer") - if not isinstance(maxfds, int) or maxfds < 1: - raise ValueError("maxfds must be a positive integer") - - fds = array.array("i") - await trio.lowlevel.checkpoint() - with self._receive_guard: - while True: - try: - message, ancdata, flags, addr = await self._trio_socket.recvmsg( - msglen, socket.CMSG_LEN(maxfds * fds.itemsize) - ) - except BaseException as exc: - self._convert_socket_error(exc) - else: - if not message and not ancdata: - raise EndOfStream - - break - - for cmsg_level, cmsg_type, cmsg_data in ancdata: - if cmsg_level != socket.SOL_SOCKET or cmsg_type != socket.SCM_RIGHTS: - raise RuntimeError( - f"Received unexpected ancillary data; message = {message!r}, " - f"cmsg_level = {cmsg_level}, cmsg_type = {cmsg_type}" - ) - - fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) - - return message, list(fds) - - async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None: - if not message: - raise ValueError("message must not be empty") - if not fds: - raise ValueError("fds must not be empty") - - filenos: list[int] = [] - for fd in fds: - if isinstance(fd, int): - filenos.append(fd) - elif isinstance(fd, IOBase): - filenos.append(fd.fileno()) - - fdarray = array.array("i", filenos) - await trio.lowlevel.checkpoint() - with self._send_guard: - while True: - try: - await self._trio_socket.sendmsg( - [message], - [ - ( - socket.SOL_SOCKET, - socket.SCM_RIGHTS, - fdarray, - ) - ], - ) - break - except BaseException as exc: - self._convert_socket_error(exc) - - -class TCPSocketListener(_TrioSocketMixin, abc.SocketListener): - def __init__(self, raw_socket: socket.socket): - super().__init__(trio.socket.from_stdlib_socket(raw_socket)) - self._accept_guard = ResourceGuard("accepting connections from") - - async def accept(self) -> SocketStream: - with self._accept_guard: - try: - trio_socket, _addr = await self._trio_socket.accept() - except BaseException as exc: - self._convert_socket_error(exc) - - trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - return SocketStream(trio_socket) - - -class UNIXSocketListener(_TrioSocketMixin, abc.SocketListener): - def __init__(self, raw_socket: socket.socket): - super().__init__(trio.socket.from_stdlib_socket(raw_socket)) - self._accept_guard = ResourceGuard("accepting connections from") - - async def accept(self) -> UNIXSocketStream: - with self._accept_guard: - try: - trio_socket, _addr = await self._trio_socket.accept() - except BaseException as exc: - self._convert_socket_error(exc) - - return UNIXSocketStream(trio_socket) - - -class UDPSocket(_TrioSocketMixin[IPSockAddrType], abc.UDPSocket): - def __init__(self, trio_socket: TrioSocketType) -> None: - super().__init__(trio_socket) - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - - async def receive(self) -> tuple[bytes, IPSockAddrType]: - with self._receive_guard: - try: - data, addr = await self._trio_socket.recvfrom(65536) - return data, convert_ipv6_sockaddr(addr) - except BaseException as exc: - self._convert_socket_error(exc) - - async def send(self, item: UDPPacketType) -> None: - with self._send_guard: - try: - await self._trio_socket.sendto(*item) - except BaseException as exc: - self._convert_socket_error(exc) - - -class ConnectedUDPSocket(_TrioSocketMixin[IPSockAddrType], abc.ConnectedUDPSocket): - def __init__(self, trio_socket: TrioSocketType) -> None: - super().__init__(trio_socket) - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - - async def receive(self) -> bytes: - with self._receive_guard: - try: - return await self._trio_socket.recv(65536) - except BaseException as exc: - self._convert_socket_error(exc) - - async def send(self, item: bytes) -> None: - with self._send_guard: - try: - await self._trio_socket.send(item) - except BaseException as exc: - self._convert_socket_error(exc) - - -class UNIXDatagramSocket(_TrioSocketMixin[str], abc.UNIXDatagramSocket): - def __init__(self, trio_socket: TrioSocketType) -> None: - super().__init__(trio_socket) - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - - async def receive(self) -> UNIXDatagramPacketType: - with self._receive_guard: - try: - data, addr = await self._trio_socket.recvfrom(65536) - return data, addr - except BaseException as exc: - self._convert_socket_error(exc) - - async def send(self, item: UNIXDatagramPacketType) -> None: - with self._send_guard: - try: - await self._trio_socket.sendto(*item) - except BaseException as exc: - self._convert_socket_error(exc) - - -class ConnectedUNIXDatagramSocket( - _TrioSocketMixin[str], abc.ConnectedUNIXDatagramSocket -): - def __init__(self, trio_socket: TrioSocketType) -> None: - super().__init__(trio_socket) - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - - async def receive(self) -> bytes: - with self._receive_guard: - try: - return await self._trio_socket.recv(65536) - except BaseException as exc: - self._convert_socket_error(exc) - - async def send(self, item: bytes) -> None: - with self._send_guard: - try: - await self._trio_socket.send(item) - except BaseException as exc: - self._convert_socket_error(exc) - - -# -# Synchronization -# - - -class Event(BaseEvent): - __slots__ = ("__original",) - - def __new__(cls) -> Event: - return object.__new__(cls) - - def __init__(self) -> None: - self.__original = trio.Event() - - def is_set(self) -> bool: - return self.__original.is_set() - - async def wait(self) -> None: - return await self.__original.wait() - - def statistics(self) -> EventStatistics: - orig_statistics = self.__original.statistics() - return EventStatistics(tasks_waiting=orig_statistics.tasks_waiting) - - def set(self) -> None: - self.__original.set() - - -class Lock(BaseLock): - __slots__ = "_fast_acquire", "__original" - - def __new__(cls, *, fast_acquire: bool = False) -> Lock: - return object.__new__(cls) - - def __init__(self, *, fast_acquire: bool = False) -> None: - self._fast_acquire = fast_acquire - self.__original = trio.Lock() - - @staticmethod - def _convert_runtime_error_msg(exc: RuntimeError) -> None: - if exc.args == ("attempt to re-acquire an already held Lock",): - exc.args = ("Attempted to acquire an already held Lock",) - - async def acquire(self) -> None: - if not self._fast_acquire: - try: - await self.__original.acquire() - except RuntimeError as exc: - self._convert_runtime_error_msg(exc) - raise - - return - - # This is the "fast path" where we don't let other tasks run - await trio.lowlevel.checkpoint_if_cancelled() - try: - self.__original.acquire_nowait() - except trio.WouldBlock: - await self.__original._lot.park() - except RuntimeError as exc: - self._convert_runtime_error_msg(exc) - raise - - def acquire_nowait(self) -> None: - try: - self.__original.acquire_nowait() - except trio.WouldBlock: - raise WouldBlock from None - except RuntimeError as exc: - self._convert_runtime_error_msg(exc) - raise - - def locked(self) -> bool: - return self.__original.locked() - - def release(self) -> None: - self.__original.release() - - def statistics(self) -> LockStatistics: - orig_statistics = self.__original.statistics() - owner = TrioTaskInfo(orig_statistics.owner) if orig_statistics.owner else None - return LockStatistics( - orig_statistics.locked, owner, orig_statistics.tasks_waiting - ) - - -class Semaphore(BaseSemaphore): - __slots__ = ("__original",) - - def __new__( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> Semaphore: - return object.__new__(cls) - - def __init__( - self, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> None: - super().__init__(initial_value, max_value=max_value, fast_acquire=fast_acquire) - self.__original = trio.Semaphore(initial_value, max_value=max_value) - - async def acquire(self) -> None: - if not self._fast_acquire: - await self.__original.acquire() - return - - # This is the "fast path" where we don't let other tasks run - await trio.lowlevel.checkpoint_if_cancelled() - try: - self.__original.acquire_nowait() - except trio.WouldBlock: - await self.__original._lot.park() - - def acquire_nowait(self) -> None: - try: - self.__original.acquire_nowait() - except trio.WouldBlock: - raise WouldBlock from None - - @property - def max_value(self) -> int | None: - return self.__original.max_value - - @property - def value(self) -> int: - return self.__original.value - - def release(self) -> None: - self.__original.release() - - def statistics(self) -> SemaphoreStatistics: - orig_statistics = self.__original.statistics() - return SemaphoreStatistics(orig_statistics.tasks_waiting) - - -class CapacityLimiter(BaseCapacityLimiter): - __slots__ = ("__original",) - - def __new__( - cls, - total_tokens: float | None = None, - *, - original: trio.CapacityLimiter | None = None, - ) -> CapacityLimiter: - return object.__new__(cls) - - def __init__( - self, - total_tokens: float | None = None, - *, - original: trio.CapacityLimiter | None = None, - ) -> None: - if original is not None: - self.__original = original - else: - assert total_tokens is not None - self.__original = trio.CapacityLimiter(total_tokens) - - async def __aenter__(self) -> None: - return await self.__original.__aenter__() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - await self.__original.__aexit__(exc_type, exc_val, exc_tb) - - @property - def total_tokens(self) -> float: - return self.__original.total_tokens - - @total_tokens.setter - def total_tokens(self, value: float) -> None: - self.__original.total_tokens = value - - @property - def borrowed_tokens(self) -> int: - return self.__original.borrowed_tokens - - @property - def available_tokens(self) -> float: - return self.__original.available_tokens - - def acquire_nowait(self) -> None: - self.__original.acquire_nowait() - - def acquire_on_behalf_of_nowait(self, borrower: object) -> None: - self.__original.acquire_on_behalf_of_nowait(borrower) - - async def acquire(self) -> None: - await self.__original.acquire() - - async def acquire_on_behalf_of(self, borrower: object) -> None: - await self.__original.acquire_on_behalf_of(borrower) - - def release(self) -> None: - return self.__original.release() - - def release_on_behalf_of(self, borrower: object) -> None: - return self.__original.release_on_behalf_of(borrower) - - def statistics(self) -> CapacityLimiterStatistics: - orig = self.__original.statistics() - return CapacityLimiterStatistics( - borrowed_tokens=orig.borrowed_tokens, - total_tokens=orig.total_tokens, - borrowers=tuple(orig.borrowers), - tasks_waiting=orig.tasks_waiting, - ) - - -_capacity_limiter_wrapper: trio.lowlevel.RunVar = RunVar("_capacity_limiter_wrapper") - - -# -# Signal handling -# - - -class _SignalReceiver: - _iterator: AsyncIterator[int] - - def __init__(self, signals: tuple[Signals, ...]): - self._signals = signals - - def __enter__(self) -> _SignalReceiver: - self._cm = trio.open_signal_receiver(*self._signals) - self._iterator = self._cm.__enter__() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool | None: - return self._cm.__exit__(exc_type, exc_val, exc_tb) - - def __aiter__(self) -> _SignalReceiver: - return self - - async def __anext__(self) -> Signals: - signum = await self._iterator.__anext__() - return Signals(signum) - - -# -# Testing and debugging -# - - -class TestRunner(abc.TestRunner): - def __init__(self, **options: Any) -> None: - from queue import Queue - - self._call_queue: Queue[Callable[[], object]] = Queue() - self._send_stream: ( - MemoryObjectSendStream[tuple[Awaitable[Any], list[Outcome]]] | None - ) = None - self._options = options - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: types.TracebackType | None, - ) -> None: - if self._send_stream: - self._send_stream.close() - while self._send_stream is not None: - self._call_queue.get()() - - def is_running(self) -> bool: - return trio.lowlevel.in_trio_task() - - async def _run_tests_and_fixtures(self) -> None: - self._send_stream, receive_stream = create_memory_object_stream[ - tuple[Awaitable[Any], list[Outcome]] - ](1) - with receive_stream: - async for awaitable, outcome_holder in receive_stream: - try: - retval = await awaitable - except BaseException as exc: - outcome_holder.append(Error(exc)) - else: - outcome_holder.append(Value(retval)) - - def _main_task_finished(self, outcome: object) -> None: - self._send_stream = None - - def _call_in_runner_task( - self, - func: Callable[P, Awaitable[T_Retval]], - /, - *args: P.args, - **kwargs: P.kwargs, - ) -> T_Retval: - if self._send_stream is None: - trio.lowlevel.start_guest_run( - self._run_tests_and_fixtures, - run_sync_soon_threadsafe=self._call_queue.put, - done_callback=self._main_task_finished, - **self._options, - ) - while self._send_stream is None: - self._call_queue.get()() - - outcome_holder: list[Outcome] = [] - self._send_stream.send_nowait((func(*args, **kwargs), outcome_holder)) - while not outcome_holder: - self._call_queue.get()() - - return outcome_holder[0].unwrap() - - def run_asyncgen_fixture( - self, - fixture_func: Callable[..., AsyncGenerator[T_Retval, Any]], - kwargs: dict[str, Any], - ) -> Iterable[T_Retval]: - asyncgen = fixture_func(**kwargs) - fixturevalue: T_Retval = self._call_in_runner_task(asyncgen.asend, None) - - yield fixturevalue - - try: - self._call_in_runner_task(asyncgen.asend, None) - except StopAsyncIteration: - pass - else: - self._call_in_runner_task(asyncgen.aclose) - raise RuntimeError("Async generator fixture did not stop") - - def run_fixture( - self, - fixture_func: Callable[..., Coroutine[Any, Any, T_Retval]], - kwargs: dict[str, Any], - ) -> T_Retval: - return self._call_in_runner_task(fixture_func, **kwargs) - - def run_test( - self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any] - ) -> None: - self._call_in_runner_task(test_func, **kwargs) - - -class TrioTaskInfo(TaskInfo): - def __init__(self, task: trio.lowlevel.Task): - parent_id = None - if task.parent_nursery and task.parent_nursery.parent_task: - parent_id = id(task.parent_nursery.parent_task) - - super().__init__(id(task), parent_id, task.name, task.coro) - self._task = weakref.proxy(task) - - def has_pending_cancellation(self) -> bool: - try: - return self._task._cancel_status.effectively_cancelled - except ReferenceError: - # If the task is no longer around, it surely doesn't have a cancellation - # pending - return False - - -class TrioBackend(AsyncBackend): - @classmethod - def run( - cls, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - args: tuple[Unpack[PosArgsT]], - kwargs: dict[str, Any], - options: dict[str, Any], - ) -> T_Retval: - assert not kwargs, "unreachable, and not supported by Trio" - return trio.run(ensure_returns_coro(func), *args, **options) - - @classmethod - def current_token(cls) -> object: - return trio.lowlevel.current_trio_token() - - @classmethod - def current_time(cls) -> float: - return trio.current_time() - - @classmethod - def cancelled_exception_class(cls) -> type[BaseException]: - return trio.Cancelled - - @classmethod - async def checkpoint(cls) -> None: - await trio.lowlevel.checkpoint() - - @classmethod - async def checkpoint_if_cancelled(cls) -> None: - await trio.lowlevel.checkpoint_if_cancelled() - - @classmethod - async def cancel_shielded_checkpoint(cls) -> None: - await trio.lowlevel.cancel_shielded_checkpoint() - - @classmethod - async def sleep(cls, delay: float) -> None: - await trio.sleep(delay) - - @classmethod - def create_cancel_scope( - cls, *, deadline: float = math.inf, shield: bool = False - ) -> abc.CancelScope: - return CancelScope(deadline=deadline, shield=shield) - - @classmethod - def current_effective_deadline(cls) -> float: - return trio.current_effective_deadline() - - @classmethod - def create_task_group(cls) -> abc.TaskGroup: - return TaskGroup() - - @classmethod - def create_event(cls) -> abc.Event: - return Event() - - @classmethod - def create_lock(cls, *, fast_acquire: bool) -> Lock: - return Lock(fast_acquire=fast_acquire) - - @classmethod - def create_semaphore( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> abc.Semaphore: - return Semaphore(initial_value, max_value=max_value, fast_acquire=fast_acquire) - - @classmethod - def create_capacity_limiter(cls, total_tokens: float) -> CapacityLimiter: - return CapacityLimiter(total_tokens) - - @classmethod - async def run_sync_in_worker_thread( - cls, - func: Callable[[Unpack[PosArgsT]], T_Retval], - args: tuple[Unpack[PosArgsT]], - abandon_on_cancel: bool = False, - limiter: abc.CapacityLimiter | None = None, - ) -> T_Retval: - def wrapper() -> T_Retval: - with claim_worker_thread(TrioBackend, token): - return func(*args) - - token = TrioBackend.current_token() - return await run_sync( - wrapper, - abandon_on_cancel=abandon_on_cancel, - limiter=cast(trio.CapacityLimiter, limiter), - ) - - @classmethod - def check_cancelled(cls) -> None: - trio.from_thread.check_cancelled() - - @classmethod - def run_async_from_thread( - cls, - func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]], - args: tuple[Unpack[PosArgsT]], - token: object, - ) -> T_co: - trio_token = cast("trio.lowlevel.TrioToken | None", token) - try: - return trio.from_thread.run(func, *args, trio_token=trio_token) - except trio.RunFinishedError: - raise RunFinishedError from None - - @classmethod - def run_sync_from_thread( - cls, - func: Callable[[Unpack[PosArgsT]], T_Retval], - args: tuple[Unpack[PosArgsT]], - token: object, - ) -> T_Retval: - trio_token = cast("trio.lowlevel.TrioToken | None", token) - try: - return trio.from_thread.run_sync(func, *args, trio_token=trio_token) - except trio.RunFinishedError: - raise RunFinishedError from None - - @classmethod - async def open_process( - cls, - command: StrOrBytesPath | Sequence[StrOrBytesPath], - *, - stdin: int | IO[Any] | None, - stdout: int | IO[Any] | None, - stderr: int | IO[Any] | None, - **kwargs: Any, - ) -> Process: - def convert_item(item: StrOrBytesPath) -> str: - str_or_bytes = os.fspath(item) - if isinstance(str_or_bytes, str): - return str_or_bytes - else: - return os.fsdecode(str_or_bytes) - - if isinstance(command, (str, bytes, PathLike)): - process = await trio.lowlevel.open_process( - convert_item(command), - stdin=stdin, - stdout=stdout, - stderr=stderr, - shell=True, - **kwargs, - ) - else: - process = await trio.lowlevel.open_process( - [convert_item(item) for item in command], - stdin=stdin, - stdout=stdout, - stderr=stderr, - shell=False, - **kwargs, - ) - - stdin_stream = SendStreamWrapper(process.stdin) if process.stdin else None - stdout_stream = ReceiveStreamWrapper(process.stdout) if process.stdout else None - stderr_stream = ReceiveStreamWrapper(process.stderr) if process.stderr else None - return Process(process, stdin_stream, stdout_stream, stderr_stream) - - @classmethod - def setup_process_pool_exit_at_shutdown(cls, workers: set[abc.Process]) -> None: - trio.lowlevel.spawn_system_task(_shutdown_process_pool, workers) - - @classmethod - async def connect_tcp( - cls, host: str, port: int, local_address: IPSockAddrType | None = None - ) -> SocketStream: - family = socket.AF_INET6 if ":" in host else socket.AF_INET - trio_socket = trio.socket.socket(family) - trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - if local_address: - await trio_socket.bind(local_address) - - try: - await trio_socket.connect((host, port)) - except BaseException: - trio_socket.close() - raise - - return SocketStream(trio_socket) - - @classmethod - async def connect_unix(cls, path: str | bytes) -> abc.UNIXSocketStream: - trio_socket = trio.socket.socket(socket.AF_UNIX) - try: - await trio_socket.connect(path) - except BaseException: - trio_socket.close() - raise - - return UNIXSocketStream(trio_socket) - - @classmethod - def create_tcp_listener(cls, sock: socket.socket) -> abc.SocketListener: - return TCPSocketListener(sock) - - @classmethod - def create_unix_listener(cls, sock: socket.socket) -> abc.SocketListener: - return UNIXSocketListener(sock) - - @classmethod - async def create_udp_socket( - cls, - family: socket.AddressFamily, - local_address: IPSockAddrType | None, - remote_address: IPSockAddrType | None, - reuse_port: bool, - ) -> UDPSocket | ConnectedUDPSocket: - trio_socket = trio.socket.socket(family=family, type=socket.SOCK_DGRAM) - - if reuse_port: - trio_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) - - if local_address: - await trio_socket.bind(local_address) - - if remote_address: - await trio_socket.connect(remote_address) - return ConnectedUDPSocket(trio_socket) - else: - return UDPSocket(trio_socket) - - @classmethod - @overload - async def create_unix_datagram_socket( - cls, raw_socket: socket.socket, remote_path: None - ) -> abc.UNIXDatagramSocket: ... - - @classmethod - @overload - async def create_unix_datagram_socket( - cls, raw_socket: socket.socket, remote_path: str | bytes - ) -> abc.ConnectedUNIXDatagramSocket: ... - - @classmethod - async def create_unix_datagram_socket( - cls, raw_socket: socket.socket, remote_path: str | bytes | None - ) -> abc.UNIXDatagramSocket | abc.ConnectedUNIXDatagramSocket: - trio_socket = trio.socket.from_stdlib_socket(raw_socket) - - if remote_path: - await trio_socket.connect(remote_path) - return ConnectedUNIXDatagramSocket(trio_socket) - else: - return UNIXDatagramSocket(trio_socket) - - @classmethod - async def getaddrinfo( - cls, - host: bytes | str | None, - port: str | int | None, - *, - family: int | AddressFamily = 0, - type: int | SocketKind = 0, - proto: int = 0, - flags: int = 0, - ) -> Sequence[ - tuple[ - AddressFamily, - SocketKind, - int, - str, - tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], - ] - ]: - return await trio.socket.getaddrinfo(host, port, family, type, proto, flags) - - @classmethod - async def getnameinfo( - cls, sockaddr: IPSockAddrType, flags: int = 0 - ) -> tuple[str, str]: - return await trio.socket.getnameinfo(sockaddr, flags) - - @classmethod - async def wait_readable(cls, obj: FileDescriptorLike) -> None: - try: - await wait_readable(obj) - except trio.ClosedResourceError as exc: - raise ClosedResourceError().with_traceback(exc.__traceback__) from None - except trio.BusyResourceError: - raise BusyResourceError("reading from") from None - - @classmethod - async def wait_writable(cls, obj: FileDescriptorLike) -> None: - try: - await wait_writable(obj) - except trio.ClosedResourceError as exc: - raise ClosedResourceError().with_traceback(exc.__traceback__) from None - except trio.BusyResourceError: - raise BusyResourceError("writing to") from None - - @classmethod - def notify_closing(cls, obj: FileDescriptorLike) -> None: - notify_closing(obj) - - @classmethod - async def wrap_listener_socket(cls, sock: socket.socket) -> abc.SocketListener: - if hasattr(socket, "AF_UNIX") and sock.family == socket.AF_UNIX: - return UNIXSocketListener(sock) - - return TCPSocketListener(sock) - - @classmethod - async def wrap_stream_socket(cls, sock: socket.socket) -> SocketStream: - trio_sock = trio.socket.from_stdlib_socket(sock) - return SocketStream(trio_sock) - - @classmethod - async def wrap_unix_stream_socket(cls, sock: socket.socket) -> UNIXSocketStream: - trio_sock = trio.socket.from_stdlib_socket(sock) - return UNIXSocketStream(trio_sock) - - @classmethod - async def wrap_udp_socket(cls, sock: socket.socket) -> UDPSocket: - trio_sock = trio.socket.from_stdlib_socket(sock) - return UDPSocket(trio_sock) - - @classmethod - async def wrap_connected_udp_socket(cls, sock: socket.socket) -> ConnectedUDPSocket: - trio_sock = trio.socket.from_stdlib_socket(sock) - return ConnectedUDPSocket(trio_sock) - - @classmethod - async def wrap_unix_datagram_socket(cls, sock: socket.socket) -> UNIXDatagramSocket: - trio_sock = trio.socket.from_stdlib_socket(sock) - return UNIXDatagramSocket(trio_sock) - - @classmethod - async def wrap_connected_unix_datagram_socket( - cls, sock: socket.socket - ) -> ConnectedUNIXDatagramSocket: - trio_sock = trio.socket.from_stdlib_socket(sock) - return ConnectedUNIXDatagramSocket(trio_sock) - - @classmethod - def current_default_thread_limiter(cls) -> CapacityLimiter: - try: - return _capacity_limiter_wrapper.get() - except LookupError: - limiter = CapacityLimiter( - original=trio.to_thread.current_default_thread_limiter() - ) - _capacity_limiter_wrapper.set(limiter) - return limiter - - @classmethod - def open_signal_receiver( - cls, *signals: Signals - ) -> AbstractContextManager[AsyncIterator[Signals]]: - return _SignalReceiver(signals) - - @classmethod - def get_current_task(cls) -> TaskInfo: - task = current_task() - return TrioTaskInfo(task) - - @classmethod - def get_running_tasks(cls) -> Sequence[TaskInfo]: - root_task = current_root_task() - assert root_task - task_infos = [TrioTaskInfo(root_task)] - nurseries = root_task.child_nurseries - while nurseries: - new_nurseries: list[trio.Nursery] = [] - for nursery in nurseries: - for task in nursery.child_tasks: - task_infos.append(TrioTaskInfo(task)) - new_nurseries.extend(task.child_nurseries) - - nurseries = new_nurseries - - return task_infos - - @classmethod - async def wait_all_tasks_blocked(cls) -> None: - from trio.testing import wait_all_tasks_blocked - - await wait_all_tasks_blocked() - - @classmethod - def create_test_runner(cls, options: dict[str, Any]) -> TestRunner: - return TestRunner(**options) - - -backend_class = TrioBackend diff --git a/server/venv/Lib/site-packages/anyio/_core/__init__.py b/server/venv/Lib/site-packages/anyio/_core/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/venv/Lib/site-packages/anyio/_core/_asyncio_selector_thread.py b/server/venv/Lib/site-packages/anyio/_core/_asyncio_selector_thread.py deleted file mode 100644 index 9f35bae..0000000 --- a/server/venv/Lib/site-packages/anyio/_core/_asyncio_selector_thread.py +++ /dev/null @@ -1,167 +0,0 @@ -from __future__ import annotations - -import asyncio -import socket -import threading -from collections.abc import Callable -from selectors import EVENT_READ, EVENT_WRITE, DefaultSelector -from typing import TYPE_CHECKING, Any - -if TYPE_CHECKING: - from _typeshed import FileDescriptorLike - -_selector_lock = threading.Lock() -_selector: Selector | None = None - - -class Selector: - def __init__(self) -> None: - self._thread = threading.Thread(target=self.run, name="AnyIO socket selector") - self._selector = DefaultSelector() - self._send, self._receive = socket.socketpair() - self._send.setblocking(False) - self._receive.setblocking(False) - # This somewhat reduces the amount of memory wasted queueing up data - # for wakeups. With these settings, maximum number of 1-byte sends - # before getting BlockingIOError: - # Linux 4.8: 6 - # macOS (darwin 15.5): 1 - # Windows 10: 525347 - # Windows you're weird. (And on Windows setting SNDBUF to 0 makes send - # blocking, even on non-blocking sockets, so don't do that.) - self._receive.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 1) - self._send.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 1) - # On Windows this is a TCP socket so this might matter. On other - # platforms this fails b/c AF_UNIX sockets aren't actually TCP. - try: - self._send.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - except OSError: - pass - - self._selector.register(self._receive, EVENT_READ) - self._closed = False - - def start(self) -> None: - self._thread.start() - threading._register_atexit(self._stop) # type: ignore[attr-defined] - - def _stop(self) -> None: - global _selector - self._closed = True - self._notify_self() - self._send.close() - self._thread.join() - self._selector.unregister(self._receive) - self._receive.close() - self._selector.close() - _selector = None - assert not self._selector.get_map(), ( - "selector still has registered file descriptors after shutdown" - ) - - def _notify_self(self) -> None: - try: - self._send.send(b"\x00") - except BlockingIOError: - pass - - def add_reader(self, fd: FileDescriptorLike, callback: Callable[[], Any]) -> None: - loop = asyncio.get_running_loop() - try: - key = self._selector.get_key(fd) - except KeyError: - self._selector.register(fd, EVENT_READ, {EVENT_READ: (loop, callback)}) - else: - if EVENT_READ in key.data: - raise ValueError( - "this file descriptor is already registered for reading" - ) - - key.data[EVENT_READ] = loop, callback - self._selector.modify(fd, key.events | EVENT_READ, key.data) - - self._notify_self() - - def add_writer(self, fd: FileDescriptorLike, callback: Callable[[], Any]) -> None: - loop = asyncio.get_running_loop() - try: - key = self._selector.get_key(fd) - except KeyError: - self._selector.register(fd, EVENT_WRITE, {EVENT_WRITE: (loop, callback)}) - else: - if EVENT_WRITE in key.data: - raise ValueError( - "this file descriptor is already registered for writing" - ) - - key.data[EVENT_WRITE] = loop, callback - self._selector.modify(fd, key.events | EVENT_WRITE, key.data) - - self._notify_self() - - def remove_reader(self, fd: FileDescriptorLike) -> bool: - try: - key = self._selector.get_key(fd) - except KeyError: - return False - - if new_events := key.events ^ EVENT_READ: - del key.data[EVENT_READ] - self._selector.modify(fd, new_events, key.data) - else: - self._selector.unregister(fd) - - return True - - def remove_writer(self, fd: FileDescriptorLike) -> bool: - try: - key = self._selector.get_key(fd) - except KeyError: - return False - - if new_events := key.events ^ EVENT_WRITE: - del key.data[EVENT_WRITE] - self._selector.modify(fd, new_events, key.data) - else: - self._selector.unregister(fd) - - return True - - def run(self) -> None: - while not self._closed: - for key, events in self._selector.select(): - if key.fileobj is self._receive: - try: - while self._receive.recv(4096): - pass - except BlockingIOError: - pass - - continue - - if events & EVENT_READ: - loop, callback = key.data[EVENT_READ] - self.remove_reader(key.fd) - try: - loop.call_soon_threadsafe(callback) - except RuntimeError: - pass # the loop was already closed - - if events & EVENT_WRITE: - loop, callback = key.data[EVENT_WRITE] - self.remove_writer(key.fd) - try: - loop.call_soon_threadsafe(callback) - except RuntimeError: - pass # the loop was already closed - - -def get_selector() -> Selector: - global _selector - - with _selector_lock: - if _selector is None: - _selector = Selector() - _selector.start() - - return _selector diff --git a/server/venv/Lib/site-packages/anyio/_core/_contextmanagers.py b/server/venv/Lib/site-packages/anyio/_core/_contextmanagers.py deleted file mode 100644 index 302f32b..0000000 --- a/server/venv/Lib/site-packages/anyio/_core/_contextmanagers.py +++ /dev/null @@ -1,200 +0,0 @@ -from __future__ import annotations - -from abc import abstractmethod -from contextlib import AbstractAsyncContextManager, AbstractContextManager -from inspect import isasyncgen, iscoroutine, isgenerator -from types import TracebackType -from typing import Protocol, TypeVar, cast, final - -_T_co = TypeVar("_T_co", covariant=True) -_ExitT_co = TypeVar("_ExitT_co", covariant=True, bound="bool | None") - - -class _SupportsCtxMgr(Protocol[_T_co, _ExitT_co]): - def __contextmanager__(self) -> AbstractContextManager[_T_co, _ExitT_co]: ... - - -class _SupportsAsyncCtxMgr(Protocol[_T_co, _ExitT_co]): - def __asynccontextmanager__( - self, - ) -> AbstractAsyncContextManager[_T_co, _ExitT_co]: ... - - -class ContextManagerMixin: - """ - Mixin class providing context manager functionality via a generator-based - implementation. - - This class allows you to implement a context manager via :meth:`__contextmanager__` - which should return a generator. The mechanics are meant to mirror those of - :func:`@contextmanager `. - - .. note:: Classes using this mix-in are not reentrant as context managers, meaning - that once you enter it, you can't re-enter before first exiting it. - - .. seealso:: :doc:`contextmanagers` - """ - - __cm: AbstractContextManager[object, bool | None] | None = None - - @final - def __enter__(self: _SupportsCtxMgr[_T_co, bool | None]) -> _T_co: - # Needed for mypy to assume self still has the __cm member - assert isinstance(self, ContextManagerMixin) - if self.__cm is not None: - raise RuntimeError( - f"this {self.__class__.__qualname__} has already been entered" - ) - - cm = self.__contextmanager__() - if not isinstance(cm, AbstractContextManager): - if isgenerator(cm): - raise TypeError( - "__contextmanager__() returned a generator object instead of " - "a context manager. Did you forget to add the @contextmanager " - "decorator?" - ) - - raise TypeError( - f"__contextmanager__() did not return a context manager object, " - f"but {cm.__class__!r}" - ) - - if cm is self: - raise TypeError( - f"{self.__class__.__qualname__}.__contextmanager__() returned " - f"self. Did you forget to add the @contextmanager decorator and a " - f"'yield' statement?" - ) - - value = cm.__enter__() - self.__cm = cm - return value - - @final - def __exit__( - self: _SupportsCtxMgr[object, _ExitT_co], - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> _ExitT_co: - # Needed for mypy to assume self still has the __cm member - assert isinstance(self, ContextManagerMixin) - if self.__cm is None: - raise RuntimeError( - f"this {self.__class__.__qualname__} has not been entered yet" - ) - - # Prevent circular references - cm = self.__cm - del self.__cm - - return cast(_ExitT_co, cm.__exit__(exc_type, exc_val, exc_tb)) - - @abstractmethod - def __contextmanager__(self) -> AbstractContextManager[object, bool | None]: - """ - Implement your context manager logic here. - - This method **must** be decorated with - :func:`@contextmanager `. - - .. note:: Remember that the ``yield`` will raise any exception raised in the - enclosed context block, so use a ``finally:`` block to clean up resources! - - :return: a context manager object - """ - - -class AsyncContextManagerMixin: - """ - Mixin class providing async context manager functionality via a generator-based - implementation. - - This class allows you to implement a context manager via - :meth:`__asynccontextmanager__`. The mechanics are meant to mirror those of - :func:`@asynccontextmanager `. - - .. note:: Classes using this mix-in are not reentrant as context managers, meaning - that once you enter it, you can't re-enter before first exiting it. - - .. seealso:: :doc:`contextmanagers` - """ - - __cm: AbstractAsyncContextManager[object, bool | None] | None = None - - @final - async def __aenter__(self: _SupportsAsyncCtxMgr[_T_co, bool | None]) -> _T_co: - # Needed for mypy to assume self still has the __cm member - assert isinstance(self, AsyncContextManagerMixin) - if self.__cm is not None: - raise RuntimeError( - f"this {self.__class__.__qualname__} has already been entered" - ) - - cm = self.__asynccontextmanager__() - if not isinstance(cm, AbstractAsyncContextManager): - if isasyncgen(cm): - raise TypeError( - "__asynccontextmanager__() returned an async generator instead of " - "an async context manager. Did you forget to add the " - "@asynccontextmanager decorator?" - ) - elif iscoroutine(cm): - cm.close() - raise TypeError( - "__asynccontextmanager__() returned a coroutine object instead of " - "an async context manager. Did you forget to add the " - "@asynccontextmanager decorator and a 'yield' statement?" - ) - - raise TypeError( - f"__asynccontextmanager__() did not return an async context manager, " - f"but {cm.__class__!r}" - ) - - if cm is self: - raise TypeError( - f"{self.__class__.__qualname__}.__asynccontextmanager__() returned " - f"self. Did you forget to add the @asynccontextmanager decorator and a " - f"'yield' statement?" - ) - - value = await cm.__aenter__() - self.__cm = cm - return value - - @final - async def __aexit__( - self: _SupportsAsyncCtxMgr[object, _ExitT_co], - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> _ExitT_co: - assert isinstance(self, AsyncContextManagerMixin) - if self.__cm is None: - raise RuntimeError( - f"this {self.__class__.__qualname__} has not been entered yet" - ) - - # Prevent circular references - cm = self.__cm - del self.__cm - - return cast(_ExitT_co, await cm.__aexit__(exc_type, exc_val, exc_tb)) - - @abstractmethod - def __asynccontextmanager__( - self, - ) -> AbstractAsyncContextManager[object, bool | None]: - """ - Implement your async context manager logic here. - - This method **must** be decorated with - :func:`@asynccontextmanager `. - - .. note:: Remember that the ``yield`` will raise any exception raised in the - enclosed context block, so use a ``finally:`` block to clean up resources! - - :return: an async context manager object - """ diff --git a/server/venv/Lib/site-packages/anyio/_core/_eventloop.py b/server/venv/Lib/site-packages/anyio/_core/_eventloop.py deleted file mode 100644 index a3e2ab1..0000000 --- a/server/venv/Lib/site-packages/anyio/_core/_eventloop.py +++ /dev/null @@ -1,240 +0,0 @@ -from __future__ import annotations - -import math -import sys -import threading -from collections.abc import Awaitable, Callable, Generator -from contextlib import contextmanager -from contextvars import Token -from importlib import import_module -from typing import TYPE_CHECKING, Any, TypeVar - -from ._exceptions import NoEventLoopError - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -sniffio: Any -try: - import sniffio -except ModuleNotFoundError: - sniffio = None - -if TYPE_CHECKING: - from ..abc import AsyncBackend - -# This must be updated when new backends are introduced -BACKENDS = "asyncio", "trio" - -T_Retval = TypeVar("T_Retval") -PosArgsT = TypeVarTuple("PosArgsT") - -threadlocals = threading.local() -loaded_backends: dict[str, type[AsyncBackend]] = {} - - -def run( - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - *args: Unpack[PosArgsT], - backend: str = "asyncio", - backend_options: dict[str, Any] | None = None, -) -> T_Retval: - """ - Run the given coroutine function in an asynchronous event loop. - - The current thread must not be already running an event loop. - - :param func: a coroutine function - :param args: positional arguments to ``func`` - :param backend: name of the asynchronous event loop implementation – currently - either ``asyncio`` or ``trio`` - :param backend_options: keyword arguments to call the backend ``run()`` - implementation with (documented :ref:`here `) - :return: the return value of the coroutine function - :raises RuntimeError: if an asynchronous event loop is already running in this - thread - :raises LookupError: if the named backend is not found - - """ - if asynclib_name := current_async_library(): - raise RuntimeError(f"Already running {asynclib_name} in this thread") - - try: - async_backend = get_async_backend(backend) - except ImportError as exc: - if backend in BACKENDS: - raise LookupError( - f"Backend {backend!r} is not available. " - f"Install it with: pip install anyio[{backend}]" - ) from exc - - raise LookupError(f"No such backend: {backend}") from exc - - token = None - if asynclib_name is None: - # Since we're in control of the event loop, we can cache the name of the async - # library - token = set_current_async_library(backend) - - try: - backend_options = backend_options or {} - return async_backend.run(func, args, {}, backend_options) - finally: - reset_current_async_library(token) - - -async def sleep(delay: float) -> None: - """ - Pause the current task for the specified duration. - - :param delay: the duration, in seconds - - """ - return await get_async_backend().sleep(delay) - - -async def sleep_forever() -> None: - """ - Pause the current task until it's cancelled. - - This is a shortcut for ``sleep(math.inf)``. - - .. versionadded:: 3.1 - - """ - await sleep(math.inf) - - -async def sleep_until(deadline: float) -> None: - """ - Pause the current task until the given time. - - :param deadline: the absolute time to wake up at (according to the internal - monotonic clock of the event loop) - - .. versionadded:: 3.1 - - """ - now = current_time() - await sleep(max(deadline - now, 0)) - - -def current_time() -> float: - """ - Return the current value of the event loop's internal clock. - - :return: the clock value (seconds) - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().current_time() - - -def get_all_backends() -> tuple[str, ...]: - """Return a tuple of the names of all built-in backends.""" - return BACKENDS - - -def get_available_backends() -> tuple[str, ...]: - """ - Test for the availability of built-in backends. - - :return a tuple of the built-in backend names that were successfully imported - - .. versionadded:: 4.12 - - """ - available_backends: list[str] = [] - for backend_name in get_all_backends(): - try: - get_async_backend(backend_name) - except ImportError: - continue - - available_backends.append(backend_name) - - return tuple(available_backends) - - -def get_cancelled_exc_class() -> type[BaseException]: - """ - Return the current async library's cancellation exception class. - - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().cancelled_exception_class() - - -# -# Private API -# - - -@contextmanager -def claim_worker_thread( - backend_class: type[AsyncBackend], token: object -) -> Generator[Any, None, None]: - from ..lowlevel import EventLoopToken - - threadlocals.current_token = EventLoopToken(backend_class, token) - try: - yield - finally: - del threadlocals.current_token - - -def get_async_backend(asynclib_name: str | None = None) -> type[AsyncBackend]: - if asynclib_name is None: - asynclib_name = current_async_library() - if not asynclib_name: - raise NoEventLoopError( - f"Not currently running on any asynchronous event loop. " - f"Available async backends: {', '.join(get_all_backends())}" - ) - - # We use our own dict instead of sys.modules to get the already imported back-end - # class because the appropriate modules in sys.modules could potentially be only - # partially initialized - try: - return loaded_backends[asynclib_name] - except KeyError: - module = import_module(f"anyio._backends._{asynclib_name}") - loaded_backends[asynclib_name] = module.backend_class - return module.backend_class - - -def current_async_library() -> str | None: - if sniffio is None: - # If sniffio is not installed, we assume we're either running asyncio or nothing - import asyncio - - try: - asyncio.get_running_loop() - return "asyncio" - except RuntimeError: - pass - else: - try: - return sniffio.current_async_library() - except sniffio.AsyncLibraryNotFoundError: - pass - - return None - - -def set_current_async_library(asynclib_name: str | None) -> Token | None: - # no-op if sniffio is not installed - if sniffio is None: - return None - - return sniffio.current_async_library_cvar.set(asynclib_name) - - -def reset_current_async_library(token: Token | None) -> None: - if token is not None: - sniffio.current_async_library_cvar.reset(token) diff --git a/server/venv/Lib/site-packages/anyio/_core/_exceptions.py b/server/venv/Lib/site-packages/anyio/_core/_exceptions.py deleted file mode 100644 index cd6eb9b..0000000 --- a/server/venv/Lib/site-packages/anyio/_core/_exceptions.py +++ /dev/null @@ -1,177 +0,0 @@ -from __future__ import annotations - -import sys -from collections.abc import Generator -from textwrap import dedent -from typing import Any - -if sys.version_info < (3, 11): - from exceptiongroup import BaseExceptionGroup - - -class BrokenResourceError(Exception): - """ - Raised when trying to use a resource that has been rendered unusable due to external - causes (e.g. a send stream whose peer has disconnected). - """ - - -class BrokenWorkerProcess(Exception): - """ - Raised by :meth:`~anyio.to_process.run_sync` if the worker process terminates abruptly or - otherwise misbehaves. - """ - - -class BrokenWorkerInterpreter(Exception): - """ - Raised by :meth:`~anyio.to_interpreter.run_sync` if an unexpected exception is - raised in the subinterpreter. - """ - - def __init__(self, excinfo: Any): - # This was adapted from concurrent.futures.interpreter.ExecutionFailed - msg = excinfo.formatted - if not msg: - if excinfo.type and excinfo.msg: - msg = f"{excinfo.type.__name__}: {excinfo.msg}" - else: - msg = excinfo.type.__name__ or excinfo.msg - - super().__init__(msg) - self.excinfo = excinfo - - def __str__(self) -> str: - try: - formatted = self.excinfo.errdisplay - except Exception: - return super().__str__() - else: - return dedent( - f""" - {super().__str__()} - - Uncaught in the interpreter: - - {formatted} - """.strip() - ) - - -class BusyResourceError(Exception): - """ - Raised when two tasks are trying to read from or write to the same resource - concurrently. - """ - - def __init__(self, action: str): - super().__init__(f"Another task is already {action} this resource") - - -class ClosedResourceError(Exception): - """Raised when trying to use a resource that has been closed.""" - - -class ConnectionFailed(OSError): - """ - Raised when a connection attempt fails. - - .. note:: This class inherits from :exc:`OSError` for backwards compatibility. - """ - - -def iterate_exceptions( - exception: BaseException, -) -> Generator[BaseException, None, None]: - if isinstance(exception, BaseExceptionGroup): - for exc in exception.exceptions: - yield from iterate_exceptions(exc) - else: - yield exception - - -class DelimiterNotFound(Exception): - """ - Raised during - :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_until` if the - maximum number of bytes has been read without the delimiter being found. - """ - - def __init__(self, max_bytes: int) -> None: - super().__init__( - f"The delimiter was not found among the first {max_bytes} bytes" - ) - - -class EndOfStream(Exception): - """ - Raised when trying to read from a stream that has been closed from the other end. - """ - - -class IncompleteRead(Exception): - """ - Raised during - :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_exactly` or - :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_until` if the - connection is closed before the requested amount of bytes has been read. - """ - - def __init__(self) -> None: - super().__init__( - "The stream was closed before the read operation could be completed" - ) - - -class TypedAttributeLookupError(LookupError): - """ - Raised by :meth:`~anyio.TypedAttributeProvider.extra` when the given typed attribute - is not found and no default value has been given. - """ - - -class WouldBlock(Exception): - """Raised by ``X_nowait`` functions if ``X()`` would block.""" - - -class NoEventLoopError(RuntimeError): - """ - Raised by several functions that require an event loop to be running in the current - thread when there is no running event loop. - - This is also raised by :func:`.from_thread.run` and :func:`.from_thread.run_sync` - if not calling from an AnyIO worker thread, and no ``token`` was passed. - """ - - -class RunFinishedError(RuntimeError): - """ - Raised by :func:`.from_thread.run` and :func:`.from_thread.run_sync` if the event - loop associated with the explicitly passed token has already finished. - """ - - def __init__(self) -> None: - super().__init__( - "The event loop associated with the given token has already finished" - ) - - -class TaskFailed(Exception): - """ - Raised when awaiting on, or attempting to access the return value of, a - :class:`.TaskHandle` that raised an exception. - """ - - -class TaskCancelled(TaskFailed): - """ - Raised when awaiting on, or attempting to access the return value of, a - :class:`.TaskHandle` that was cancelled. - """ - - -class TaskNotFinished(Exception): - """ - Raised when attempting to access the return value or exception of a - :class:`.TaskHandle` that is still pending completion. - """ diff --git a/server/venv/Lib/site-packages/anyio/_core/_fileio.py b/server/venv/Lib/site-packages/anyio/_core/_fileio.py deleted file mode 100644 index 692c754..0000000 --- a/server/venv/Lib/site-packages/anyio/_core/_fileio.py +++ /dev/null @@ -1,960 +0,0 @@ -from __future__ import annotations - -import os -import pathlib -import sys -from collections.abc import ( - AsyncIterator, - Callable, - Iterable, - Iterator, - Sequence, -) -from dataclasses import dataclass -from functools import partial -from os import PathLike -from typing import ( - IO, - TYPE_CHECKING, - Any, - AnyStr, - ClassVar, - Final, - Generic, - TypeVar, - overload, -) - -from .. import to_thread -from ..abc import AsyncResource -from ._synchronization import CapacityLimiter - -if sys.version_info >= (3, 11): - from typing import Self -else: - from typing_extensions import Self - -if sys.version_info >= (3, 14): - from pathlib.types import PathInfo - -if TYPE_CHECKING: - from types import ModuleType - - from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer -else: - ReadableBuffer = OpenBinaryMode = OpenTextMode = WriteableBuffer = object - - -T = TypeVar("T", bound="Path") - - -class AsyncFile(AsyncResource, Generic[AnyStr]): - """ - An asynchronous file object. - - This class wraps a standard file object and provides async friendly versions of the - following blocking methods (where available on the original file object): - - * read - * read1 - * readline - * readlines - * readinto - * readinto1 - * write - * writelines - * truncate - * seek - * tell - * flush - - All other methods are directly passed through. - - This class supports the asynchronous context manager protocol which closes the - underlying file at the end of the context block. - - This class also supports asynchronous iteration:: - - async with await open_file(...) as f: - async for line in f: - print(line) - """ - - def __init__( - self, fp: IO[AnyStr], *, limiter: CapacityLimiter | None = None - ) -> None: - if limiter is not None and not isinstance(limiter, CapacityLimiter): - raise TypeError( - f"limiter must be a CapacityLimiter or None, not " - f"{limiter.__class__.__name__}" - ) - - self._fp: Any = fp - self._limiter = limiter - - def __getattr__(self, name: str) -> object: - return getattr(self._fp, name) - - @property - def limiter(self) -> CapacityLimiter | None: - """The capacity limiter used by this file object, if not the global limiter.""" - return self._limiter - - @property - def wrapped(self) -> IO[AnyStr]: - """The wrapped file object.""" - return self._fp - - async def __aiter__(self) -> AsyncIterator[AnyStr]: - while True: - line = await self.readline() - if line: - yield line - else: - break - - async def aclose(self) -> None: - return await to_thread.run_sync(self._fp.close, limiter=self._limiter) - - async def read(self, size: int = -1) -> AnyStr: - return await to_thread.run_sync(self._fp.read, size, limiter=self._limiter) - - async def read1(self: AsyncFile[bytes], size: int = -1) -> bytes: - return await to_thread.run_sync(self._fp.read1, size, limiter=self._limiter) - - async def readline(self) -> AnyStr: - return await to_thread.run_sync(self._fp.readline, limiter=self._limiter) - - async def readlines(self) -> list[AnyStr]: - return await to_thread.run_sync(self._fp.readlines, limiter=self._limiter) - - async def readinto(self: AsyncFile[bytes], b: WriteableBuffer) -> int: - return await to_thread.run_sync(self._fp.readinto, b, limiter=self._limiter) - - async def readinto1(self: AsyncFile[bytes], b: WriteableBuffer) -> int: - return await to_thread.run_sync(self._fp.readinto1, b, limiter=self._limiter) - - @overload - async def write(self: AsyncFile[bytes], b: ReadableBuffer) -> int: ... - - @overload - async def write(self: AsyncFile[str], b: str) -> int: ... - - async def write(self, b: ReadableBuffer | str) -> int: - return await to_thread.run_sync(self._fp.write, b, limiter=self._limiter) - - @overload - async def writelines( - self: AsyncFile[bytes], lines: Iterable[ReadableBuffer] - ) -> None: ... - - @overload - async def writelines(self: AsyncFile[str], lines: Iterable[str]) -> None: ... - - async def writelines(self, lines: Iterable[ReadableBuffer] | Iterable[str]) -> None: - return await to_thread.run_sync( - self._fp.writelines, lines, limiter=self._limiter - ) - - async def truncate(self, size: int | None = None) -> int: - return await to_thread.run_sync(self._fp.truncate, size, limiter=self._limiter) - - async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int: - return await to_thread.run_sync( - self._fp.seek, offset, whence, limiter=self._limiter - ) - - async def tell(self) -> int: - return await to_thread.run_sync(self._fp.tell, limiter=self._limiter) - - async def flush(self) -> None: - return await to_thread.run_sync(self._fp.flush, limiter=self._limiter) - - -@overload -async def open_file( - file: str | PathLike[str] | int, - mode: OpenBinaryMode, - buffering: int = ..., - encoding: str | None = ..., - errors: str | None = ..., - newline: str | None = ..., - closefd: bool = ..., - opener: Callable[[str, int], int] | None = ..., - *, - limiter: CapacityLimiter | None = ..., -) -> AsyncFile[bytes]: ... - - -@overload -async def open_file( - file: str | PathLike[str] | int, - mode: OpenTextMode = ..., - buffering: int = ..., - encoding: str | None = ..., - errors: str | None = ..., - newline: str | None = ..., - closefd: bool = ..., - opener: Callable[[str, int], int] | None = ..., - *, - limiter: CapacityLimiter | None = ..., -) -> AsyncFile[str]: ... - - -async def open_file( - file: str | PathLike[str] | int, - mode: str = "r", - buffering: int = -1, - encoding: str | None = None, - errors: str | None = None, - newline: str | None = None, - closefd: bool = True, - opener: Callable[[str, int], int] | None = None, - *, - limiter: CapacityLimiter | None = None, -) -> AsyncFile[Any]: - """ - Open a file asynchronously. - - Except for ``limiter``, the arguments are exactly the same as for the builtin :func:`open`. - - :param limiter: an optional capacity limiter to use with the file - instead of the default one - :return: an asynchronous file object - - .. versionchanged:: 4.14.0 - Added the ``limiter`` keyword argument. - - """ - fp = await to_thread.run_sync( - open, - file, - mode, - buffering, - encoding, - errors, - newline, - closefd, - opener, - limiter=limiter, - ) - return AsyncFile(fp, limiter=limiter) - - -def wrap_file( - file: IO[AnyStr], *, limiter: CapacityLimiter | None = None -) -> AsyncFile[AnyStr]: - """ - Wrap an existing file as an asynchronous file. - - :param file: an existing file-like object - :param limiter: an optional capacity limiter to use with the file - instead of the default one - :return: an asynchronous file object - - .. versionchanged:: 4.14.0 - Added the ``limiter`` keyword argument. - - """ - return AsyncFile(file, limiter=limiter) - - -@dataclass(eq=False) -class _PathIterator(AsyncIterator[T]): - iterator: Iterator[PathLike[str]] - limiter: CapacityLimiter | None - # This was added to ensure that iterating over a subclass of Path yields instances - # of that subclass rather than the base Path class. - path_cls: type[T] - - async def __anext__(self) -> T: - nextval = await to_thread.run_sync( - next, self.iterator, None, abandon_on_cancel=True, limiter=self.limiter - ) - if nextval is None: - raise StopAsyncIteration from None - - return self.path_cls(nextval, limiter=self.limiter) - - -class Path: - """ - An asynchronous version of :class:`pathlib.Path`. - - This class cannot be substituted for :class:`pathlib.Path` or - :class:`pathlib.PurePath`, but it is compatible with the :class:`os.PathLike` - interface. - - It implements the Python 3.10 version of :class:`pathlib.Path` interface, except for - the deprecated :meth:`~pathlib.Path.link_to` method. - - Some methods may be unavailable or have limited functionality, based on the Python - version: - - * :meth:`~pathlib.Path.copy` (available on Python 3.14 or later) - * :meth:`~pathlib.Path.copy_into` (available on Python 3.14 or later) - * :meth:`~pathlib.Path.from_uri` (available on Python 3.13 or later) - * :meth:`~pathlib.PurePath.full_match` (available on Python 3.13 or later) - * :attr:`~pathlib.Path.info` (available on Python 3.14 or later) - * :meth:`~pathlib.Path.is_junction` (available on Python 3.12 or later) - * :meth:`~pathlib.PurePath.match` (the ``case_sensitive`` parameter is only - available on Python 3.13 or later) - * :meth:`~pathlib.Path.move` (available on Python 3.14 or later) - * :meth:`~pathlib.Path.move_into` (available on Python 3.14 or later) - * :meth:`~pathlib.PurePath.relative_to` (the ``walk_up`` parameter is only available - on Python 3.12 or later) - * :meth:`~pathlib.Path.walk` (available on Python 3.12 or later) - - Any methods that do disk I/O need to be awaited on. These methods are: - - * :meth:`~pathlib.Path.absolute` - * :meth:`~pathlib.Path.chmod` - * :meth:`~pathlib.Path.cwd` - * :meth:`~pathlib.Path.exists` - * :meth:`~pathlib.Path.expanduser` - * :meth:`~pathlib.Path.group` - * :meth:`~pathlib.Path.hardlink_to` - * :meth:`~pathlib.Path.home` - * :meth:`~pathlib.Path.is_block_device` - * :meth:`~pathlib.Path.is_char_device` - * :meth:`~pathlib.Path.is_dir` - * :meth:`~pathlib.Path.is_fifo` - * :meth:`~pathlib.Path.is_file` - * :meth:`~pathlib.Path.is_junction` - * :meth:`~pathlib.Path.is_mount` - * :meth:`~pathlib.Path.is_socket` - * :meth:`~pathlib.Path.is_symlink` - * :meth:`~pathlib.Path.lchmod` - * :meth:`~pathlib.Path.lstat` - * :meth:`~pathlib.Path.mkdir` - * :meth:`~pathlib.Path.open` - * :meth:`~pathlib.Path.owner` - * :meth:`~pathlib.Path.read_bytes` - * :meth:`~pathlib.Path.read_text` - * :meth:`~pathlib.Path.readlink` - * :meth:`~pathlib.Path.rename` - * :meth:`~pathlib.Path.replace` - * :meth:`~pathlib.Path.resolve` - * :meth:`~pathlib.Path.rmdir` - * :meth:`~pathlib.Path.samefile` - * :meth:`~pathlib.Path.stat` - * :meth:`~pathlib.Path.symlink_to` - * :meth:`~pathlib.Path.touch` - * :meth:`~pathlib.Path.unlink` - * :meth:`~pathlib.Path.walk` - * :meth:`~pathlib.Path.write_bytes` - * :meth:`~pathlib.Path.write_text` - - Additionally, the following methods return an async iterator yielding - :class:`~.Path` objects: - - * :meth:`~pathlib.Path.glob` - * :meth:`~pathlib.Path.iterdir` - * :meth:`~pathlib.Path.rglob` - - .. versionchanged:: 4.14.0 - Added the ``limiter`` keyword argument. - """ - - __slots__ = "_path", "_limiter", "__weakref__" - - __weakref__: Any - - def __init__( - self, *args: str | PathLike[str], limiter: CapacityLimiter | None = None - ) -> None: - if limiter is not None and not isinstance(limiter, CapacityLimiter): - raise TypeError( - f"limiter must be a CapacityLimiter or None, not " - f"{limiter.__class__.__name__}" - ) - - self._path: Final[pathlib.Path] = pathlib.Path(*args) - self._limiter = limiter - - def __fspath__(self) -> str: - return self._path.__fspath__() - - if sys.version_info >= (3, 15): - - def __vfspath__(self) -> str: - return self._path.__vfspath__() - - def __str__(self) -> str: - return self._path.__str__() - - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self.as_posix()!r})" - - def __bytes__(self) -> bytes: - return self._path.__bytes__() - - def __hash__(self) -> int: - return self._path.__hash__() - - def __eq__(self, other: object) -> bool: - target = other._path if isinstance(other, Path) else other - return self._path.__eq__(target) - - def __lt__(self, other: pathlib.PurePath | Path) -> bool: - target = other._path if isinstance(other, Path) else other - return self._path.__lt__(target) - - def __le__(self, other: pathlib.PurePath | Path) -> bool: - target = other._path if isinstance(other, Path) else other - return self._path.__le__(target) - - def __gt__(self, other: pathlib.PurePath | Path) -> bool: - target = other._path if isinstance(other, Path) else other - return self._path.__gt__(target) - - def __ge__(self, other: pathlib.PurePath | Path) -> bool: - target = other._path if isinstance(other, Path) else other - return self._path.__ge__(target) - - def __truediv__(self, other: str | PathLike[str]) -> Self: - return type(self)(self._path / other, limiter=self._limiter) - - def __rtruediv__(self, other: str | PathLike[str]) -> Self: - return type(self)(other, limiter=self._limiter) / self - - @property - def limiter(self) -> CapacityLimiter | None: - """The capacity limiter used by this path, if not the global limiter.""" - return self._limiter - - @property - def parts(self) -> tuple[str, ...]: - return self._path.parts - - @property - def drive(self) -> str: - return self._path.drive - - @property - def root(self) -> str: - return self._path.root - - @property - def anchor(self) -> str: - return self._path.anchor - - @property - def parents(self) -> Sequence[Self]: - return tuple(type(self)(p, limiter=self._limiter) for p in self._path.parents) - - @property - def parent(self) -> Self: - return type(self)(self._path.parent, limiter=self._limiter) - - @property - def name(self) -> str: - return self._path.name - - @property - def suffix(self) -> str: - return self._path.suffix - - @property - def suffixes(self) -> list[str]: - return self._path.suffixes - - @property - def stem(self) -> str: - return self._path.stem - - async def absolute(self) -> Self: - path = await to_thread.run_sync(self._path.absolute, limiter=self._limiter) - return type(self)(path, limiter=self._limiter) - - def as_posix(self) -> str: - return self._path.as_posix() - - def as_uri(self) -> str: - return self._path.as_uri() - - if sys.version_info >= (3, 13): - parser: ClassVar[ModuleType] = pathlib.Path.parser - - @classmethod - def from_uri(cls, uri: str, *, limiter: CapacityLimiter | None = None) -> Self: - return cls(pathlib.Path.from_uri(uri), limiter=limiter) - - def full_match( - self, path_pattern: str, *, case_sensitive: bool | None = None - ) -> bool: - return self._path.full_match(path_pattern, case_sensitive=case_sensitive) - - def match( - self, path_pattern: str, *, case_sensitive: bool | None = None - ) -> bool: - return self._path.match(path_pattern, case_sensitive=case_sensitive) - else: - - def match(self, path_pattern: str) -> bool: - return self._path.match(path_pattern) - - if sys.version_info >= (3, 14): - - @property - def info(self) -> PathInfo: - return self._path.info - - async def copy( - self, - target: str | os.PathLike[str], - *, - follow_symlinks: bool = True, - preserve_metadata: bool = False, - ) -> Self: - func = partial( - self._path.copy, - follow_symlinks=follow_symlinks, - preserve_metadata=preserve_metadata, - ) - return type(self)( - await to_thread.run_sync( - func, pathlib.Path(target), limiter=self._limiter - ), - limiter=self._limiter, - ) - - async def copy_into( - self, - target_dir: str | os.PathLike[str], - *, - follow_symlinks: bool = True, - preserve_metadata: bool = False, - ) -> Self: - func = partial( - self._path.copy_into, - follow_symlinks=follow_symlinks, - preserve_metadata=preserve_metadata, - ) - return type(self)( - await to_thread.run_sync( - func, pathlib.Path(target_dir), limiter=self._limiter - ), - limiter=self._limiter, - ) - - async def move(self, target: str | os.PathLike[str]) -> Self: - # Upstream does not handle anyio.Path properly as a PathLike - target = pathlib.Path(target) - return type(self)( - await to_thread.run_sync( - self._path.move, target, limiter=self._limiter - ), - limiter=self._limiter, - ) - - async def move_into( - self, - target_dir: str | os.PathLike[str], - ) -> Self: - return type(self)( - await to_thread.run_sync( - self._path.move_into, target_dir, limiter=self._limiter - ), - limiter=self._limiter, - ) - - def is_relative_to(self, other: str | PathLike[str]) -> bool: - try: - self.relative_to(other) - return True - except ValueError: - return False - - async def chmod(self, mode: int, *, follow_symlinks: bool = True) -> None: - func = partial(os.chmod, follow_symlinks=follow_symlinks) - return await to_thread.run_sync(func, self._path, mode, limiter=self._limiter) - - @classmethod - async def cwd(cls, *, limiter: CapacityLimiter | None = None) -> Self: - path = await to_thread.run_sync(pathlib.Path.cwd, limiter=limiter) - return cls(path, limiter=limiter) - - async def exists(self) -> bool: - return await to_thread.run_sync( - self._path.exists, abandon_on_cancel=True, limiter=self._limiter - ) - - async def expanduser(self) -> Self: - return type(self)( - await to_thread.run_sync( - self._path.expanduser, abandon_on_cancel=True, limiter=self._limiter - ), - limiter=self._limiter, - ) - - if sys.version_info < (3, 12): - # Python 3.11 and earlier - def glob(self, pattern: str) -> AsyncIterator[Self]: - gen = self._path.glob(pattern) - return _PathIterator(gen, self._limiter, type(self)) - elif (3, 12) <= sys.version_info < (3, 13): - # changed in Python 3.12: - # - The case_sensitive parameter was added. - def glob( - self, - pattern: str, - *, - case_sensitive: bool | None = None, - ) -> AsyncIterator[Self]: - gen = self._path.glob(pattern, case_sensitive=case_sensitive) - return _PathIterator(gen, self._limiter, type(self)) - elif sys.version_info >= (3, 13): - # Changed in Python 3.13: - # - The recurse_symlinks parameter was added. - # - The pattern parameter accepts a path-like object. - def glob( # type: ignore[misc] # mypy doesn't allow for differing signatures in a conditional block - self, - pattern: str | PathLike[str], - *, - case_sensitive: bool | None = None, - recurse_symlinks: bool = False, - ) -> AsyncIterator[Self]: - gen = self._path.glob( - pattern, # type: ignore[arg-type] - case_sensitive=case_sensitive, - recurse_symlinks=recurse_symlinks, - ) - return _PathIterator(gen, self._limiter, type(self)) - - async def group(self) -> str: - return await to_thread.run_sync( - self._path.group, abandon_on_cancel=True, limiter=self._limiter - ) - - async def hardlink_to( - self, target: str | bytes | PathLike[str] | PathLike[bytes] - ) -> None: - if isinstance(target, Path): - target = target._path - - await to_thread.run_sync(os.link, target, self, limiter=self._limiter) - - @classmethod - async def home(cls, *, limiter: CapacityLimiter | None = None) -> Self: - home_path = await to_thread.run_sync(pathlib.Path.home, limiter=limiter) - return cls(home_path, limiter=limiter) - - def is_absolute(self) -> bool: - return self._path.is_absolute() - - async def is_block_device(self) -> bool: - return await to_thread.run_sync( - self._path.is_block_device, abandon_on_cancel=True, limiter=self._limiter - ) - - async def is_char_device(self) -> bool: - return await to_thread.run_sync( - self._path.is_char_device, abandon_on_cancel=True, limiter=self._limiter - ) - - async def is_dir(self) -> bool: - return await to_thread.run_sync( - self._path.is_dir, abandon_on_cancel=True, limiter=self._limiter - ) - - async def is_fifo(self) -> bool: - return await to_thread.run_sync( - self._path.is_fifo, abandon_on_cancel=True, limiter=self._limiter - ) - - async def is_file(self) -> bool: - return await to_thread.run_sync( - self._path.is_file, abandon_on_cancel=True, limiter=self._limiter - ) - - if sys.version_info >= (3, 12): - - async def is_junction(self) -> bool: - return await to_thread.run_sync( - self._path.is_junction, limiter=self._limiter - ) - - async def is_mount(self) -> bool: - return await to_thread.run_sync( - os.path.ismount, self._path, abandon_on_cancel=True, limiter=self._limiter - ) - - if sys.version_info < (3, 15): - - def is_reserved(self) -> bool: - return self._path.is_reserved() - - async def is_socket(self) -> bool: - return await to_thread.run_sync( - self._path.is_socket, abandon_on_cancel=True, limiter=self._limiter - ) - - async def is_symlink(self) -> bool: - return await to_thread.run_sync( - self._path.is_symlink, abandon_on_cancel=True, limiter=self._limiter - ) - - async def iterdir(self) -> AsyncIterator[Self]: - gen = ( - self._path.iterdir() - if sys.version_info < (3, 13) - else await to_thread.run_sync( - self._path.iterdir, abandon_on_cancel=True, limiter=self._limiter - ) - ) - async for path in _PathIterator(gen, self._limiter, type(self)): - yield path - - def joinpath(self, *args: str | PathLike[str]) -> Self: - return type(self)(self._path.joinpath(*args), limiter=self._limiter) - - async def lchmod(self, mode: int) -> None: - await to_thread.run_sync(self._path.lchmod, mode, limiter=self._limiter) - - async def lstat(self) -> os.stat_result: - return await to_thread.run_sync( - self._path.lstat, abandon_on_cancel=True, limiter=self._limiter - ) - - async def mkdir( - self, mode: int = 0o777, parents: bool = False, exist_ok: bool = False - ) -> None: - await to_thread.run_sync( - self._path.mkdir, mode, parents, exist_ok, limiter=self._limiter - ) - - @overload - async def open( - self, - mode: OpenBinaryMode, - buffering: int = ..., - encoding: str | None = ..., - errors: str | None = ..., - newline: str | None = ..., - ) -> AsyncFile[bytes]: ... - - @overload - async def open( - self, - mode: OpenTextMode = ..., - buffering: int = ..., - encoding: str | None = ..., - errors: str | None = ..., - newline: str | None = ..., - ) -> AsyncFile[str]: ... - - async def open( - self, - mode: str = "r", - buffering: int = -1, - encoding: str | None = None, - errors: str | None = None, - newline: str | None = None, - ) -> AsyncFile[Any]: - fp = await to_thread.run_sync( - self._path.open, - mode, - buffering, - encoding, - errors, - newline, - limiter=self._limiter, - ) - return AsyncFile(fp, limiter=self._limiter) - - async def owner(self) -> str: - return await to_thread.run_sync( - self._path.owner, abandon_on_cancel=True, limiter=self._limiter - ) - - async def read_bytes(self) -> bytes: - return await to_thread.run_sync(self._path.read_bytes, limiter=self._limiter) - - async def read_text( - self, encoding: str | None = None, errors: str | None = None - ) -> str: - return await to_thread.run_sync( - self._path.read_text, encoding, errors, limiter=self._limiter - ) - - if sys.version_info >= (3, 12): - - def relative_to( - self, *other: str | PathLike[str], walk_up: bool = False - ) -> Self: - # relative_to() should work with any PathLike but it doesn't - others = [pathlib.Path(other) for other in other] - return type(self)( - self._path.relative_to(*others, walk_up=walk_up), limiter=self._limiter - ) - - else: - - def relative_to(self, *other: str | PathLike[str]) -> Self: - return type(self)(self._path.relative_to(*other), limiter=self._limiter) - - async def readlink(self) -> Self: - target = await to_thread.run_sync( - os.readlink, self._path, limiter=self._limiter - ) - return type(self)(target, limiter=self._limiter) - - async def rename(self, target: str | pathlib.PurePath | Path) -> Self: - if isinstance(target, Path): - target = target._path - - await to_thread.run_sync(self._path.rename, target, limiter=self._limiter) - return type(self)(target, limiter=self._limiter) - - async def replace(self, target: str | pathlib.PurePath | Path) -> Self: - if isinstance(target, Path): - target = target._path - - await to_thread.run_sync(self._path.replace, target, limiter=self._limiter) - return type(self)(target, limiter=self._limiter) - - async def resolve(self, strict: bool = False) -> Self: - func = partial(self._path.resolve, strict=strict) - return type(self)( - await to_thread.run_sync( - func, abandon_on_cancel=True, limiter=self._limiter - ), - limiter=self._limiter, - ) - - if sys.version_info < (3, 12): - # Pre Python 3.12 - def rglob(self, pattern: str) -> AsyncIterator[Self]: - gen = self._path.rglob(pattern) - return _PathIterator(gen, self._limiter, type(self)) - elif (3, 12) <= sys.version_info < (3, 13): - # Changed in Python 3.12: - # - The case_sensitive parameter was added. - def rglob( - self, pattern: str, *, case_sensitive: bool | None = None - ) -> AsyncIterator[Self]: - gen = self._path.rglob(pattern, case_sensitive=case_sensitive) - return _PathIterator(gen, self._limiter, type(self)) - elif sys.version_info >= (3, 13): - # Changed in Python 3.13: - # - The recurse_symlinks parameter was added. - # - The pattern parameter accepts a path-like object. - def rglob( # type: ignore[misc] # mypy doesn't allow for differing signatures in a conditional block - self, - pattern: str | PathLike[str], - *, - case_sensitive: bool | None = None, - recurse_symlinks: bool = False, - ) -> AsyncIterator[Self]: - gen = self._path.rglob( - pattern, # type: ignore[arg-type] - case_sensitive=case_sensitive, - recurse_symlinks=recurse_symlinks, - ) - return _PathIterator(gen, self._limiter, type(self)) - - async def rmdir(self) -> None: - await to_thread.run_sync(self._path.rmdir, limiter=self._limiter) - - async def samefile(self, other_path: str | PathLike[str]) -> bool: - if isinstance(other_path, Path): - other_path = other_path._path - - return await to_thread.run_sync( - self._path.samefile, - other_path, - abandon_on_cancel=True, - limiter=self._limiter, - ) - - async def stat(self, *, follow_symlinks: bool = True) -> os.stat_result: - func = partial(os.stat, follow_symlinks=follow_symlinks) - return await to_thread.run_sync( - func, self._path, abandon_on_cancel=True, limiter=self._limiter - ) - - async def symlink_to( - self, - target: str | bytes | PathLike[str] | PathLike[bytes], - target_is_directory: bool = False, - ) -> None: - if isinstance(target, Path): - target = target._path - - await to_thread.run_sync( - self._path.symlink_to, target, target_is_directory, limiter=self._limiter - ) - - async def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None: - await to_thread.run_sync( - self._path.touch, mode, exist_ok, limiter=self._limiter - ) - - async def unlink(self, missing_ok: bool = False) -> None: - try: - await to_thread.run_sync(self._path.unlink, limiter=self._limiter) - except FileNotFoundError: - if not missing_ok: - raise - - if sys.version_info >= (3, 12): - - async def walk( - self, - top_down: bool = True, - on_error: Callable[[OSError], object] | None = None, - follow_symlinks: bool = False, - ) -> AsyncIterator[tuple[Self, list[str], list[str]]]: - def get_next_value() -> tuple[pathlib.Path, list[str], list[str]] | None: - try: - return next(gen) - except StopIteration: - return None - - gen = self._path.walk(top_down, on_error, follow_symlinks) - while True: - value = await to_thread.run_sync(get_next_value, limiter=self._limiter) - if value is None: - return - - root, dirs, paths = value - yield type(self)(root, limiter=self._limiter), dirs, paths - - def with_name(self, name: str) -> Self: - return type(self)(self._path.with_name(name), limiter=self._limiter) - - def with_stem(self, stem: str) -> Self: - return type(self)( - self._path.with_name(stem + self._path.suffix), limiter=self._limiter - ) - - def with_suffix(self, suffix: str) -> Self: - return type(self)(self._path.with_suffix(suffix), limiter=self._limiter) - - def with_segments(self, *pathsegments: str | PathLike[str]) -> Self: - return type(self)(*pathsegments, limiter=self._limiter) - - async def write_bytes(self, data: ReadableBuffer) -> int: - return await to_thread.run_sync( - self._path.write_bytes, data, limiter=self._limiter - ) - - async def write_text( - self, - data: str, - encoding: str | None = None, - errors: str | None = None, - newline: str | None = None, - ) -> int: - return await to_thread.run_sync( - self._path.write_text, - data, - encoding, - errors, - newline, - limiter=self._limiter, - ) - - -PathLike.register(Path) diff --git a/server/venv/Lib/site-packages/anyio/_core/_resources.py b/server/venv/Lib/site-packages/anyio/_core/_resources.py deleted file mode 100644 index b9a5344..0000000 --- a/server/venv/Lib/site-packages/anyio/_core/_resources.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import annotations - -from ..abc import AsyncResource -from ._tasks import CancelScope - - -async def aclose_forcefully(resource: AsyncResource) -> None: - """ - Close an asynchronous resource in a cancelled scope. - - Doing this closes the resource without waiting on anything. - - :param resource: the resource to close - - """ - with CancelScope() as scope: - scope.cancel() - await resource.aclose() diff --git a/server/venv/Lib/site-packages/anyio/_core/_signals.py b/server/venv/Lib/site-packages/anyio/_core/_signals.py deleted file mode 100644 index e24c79e..0000000 --- a/server/venv/Lib/site-packages/anyio/_core/_signals.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import annotations - -from collections.abc import AsyncIterator -from contextlib import AbstractContextManager -from signal import Signals - -from ._eventloop import get_async_backend - - -def open_signal_receiver( - *signals: Signals, -) -> AbstractContextManager[AsyncIterator[Signals]]: - """ - Start receiving operating system signals. - - :param signals: signals to receive (e.g. ``signal.SIGINT``) - :return: an asynchronous context manager for an asynchronous iterator which yields - signal numbers - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - .. warning:: Windows does not support signals natively so it is best to avoid - relying on this in cross-platform applications. - - .. warning:: On asyncio, this permanently replaces any previous signal handler for - the given signals, as set via :meth:`~asyncio.loop.add_signal_handler`. - - """ - return get_async_backend().open_signal_receiver(*signals) diff --git a/server/venv/Lib/site-packages/anyio/_core/_sockets.py b/server/venv/Lib/site-packages/anyio/_core/_sockets.py deleted file mode 100644 index 29f7332..0000000 --- a/server/venv/Lib/site-packages/anyio/_core/_sockets.py +++ /dev/null @@ -1,1011 +0,0 @@ -from __future__ import annotations - -import errno -import os -import socket -import ssl -import stat -import sys -from collections.abc import Awaitable -from dataclasses import dataclass -from ipaddress import IPv4Address, IPv6Address, ip_address -from os import PathLike, chmod -from socket import AddressFamily, SocketKind -from typing import TYPE_CHECKING, Any, Literal, cast, overload - -from .. import ConnectionFailed, to_thread -from ..abc import ( - ByteStreamConnectable, - ConnectedUDPSocket, - ConnectedUNIXDatagramSocket, - IPAddressType, - IPSockAddrType, - SocketListener, - SocketStream, - UDPSocket, - UNIXDatagramSocket, - UNIXSocketStream, -) -from ..streams.stapled import MultiListener -from ..streams.tls import TLSConnectable, TLSStream -from ._eventloop import get_async_backend -from ._resources import aclose_forcefully -from ._synchronization import Event -from ._tasks import create_task_group, move_on_after - -if TYPE_CHECKING: - from _typeshed import FileDescriptorLike -else: - FileDescriptorLike = object - -if sys.version_info < (3, 11): - from exceptiongroup import ExceptionGroup - -if sys.version_info >= (3, 12): - from typing import override -else: - from typing_extensions import override - -if sys.version_info < (3, 13): - from typing_extensions import deprecated -else: - from warnings import deprecated - -IPPROTO_IPV6 = getattr(socket, "IPPROTO_IPV6", 41) # https://bugs.python.org/issue29515 - -AnyIPAddressFamily = Literal[ - AddressFamily.AF_UNSPEC, AddressFamily.AF_INET, AddressFamily.AF_INET6 -] -IPAddressFamily = Literal[AddressFamily.AF_INET, AddressFamily.AF_INET6] - - -# tls_hostname given -@overload -async def connect_tcp( - remote_host: IPAddressType, - remote_port: int, - *, - local_host: IPAddressType | None = ..., - local_port: int | None = ..., - ssl_context: ssl.SSLContext | None = ..., - tls_standard_compatible: bool = ..., - tls_hostname: str, - happy_eyeballs_delay: float = ..., -) -> TLSStream: ... - - -# ssl_context given -@overload -async def connect_tcp( - remote_host: IPAddressType, - remote_port: int, - *, - local_host: IPAddressType | None = ..., - local_port: int | None = ..., - ssl_context: ssl.SSLContext, - tls_standard_compatible: bool = ..., - tls_hostname: str | None = ..., - happy_eyeballs_delay: float = ..., -) -> TLSStream: ... - - -# tls=True -@overload -async def connect_tcp( - remote_host: IPAddressType, - remote_port: int, - *, - local_host: IPAddressType | None = ..., - local_port: int | None = ..., - tls: Literal[True], - ssl_context: ssl.SSLContext | None = ..., - tls_standard_compatible: bool = ..., - tls_hostname: str | None = ..., - happy_eyeballs_delay: float = ..., -) -> TLSStream: ... - - -# tls=False -@overload -async def connect_tcp( - remote_host: IPAddressType, - remote_port: int, - *, - local_host: IPAddressType | None = ..., - local_port: int | None = ..., - tls: Literal[False], - ssl_context: ssl.SSLContext | None = ..., - tls_standard_compatible: bool = ..., - tls_hostname: str | None = ..., - happy_eyeballs_delay: float = ..., -) -> SocketStream: ... - - -# No TLS arguments -@overload -async def connect_tcp( - remote_host: IPAddressType, - remote_port: int, - *, - local_host: IPAddressType | None = ..., - local_port: int | None = ..., - happy_eyeballs_delay: float = ..., -) -> SocketStream: ... - - -async def connect_tcp( - remote_host: IPAddressType, - remote_port: int, - *, - local_host: IPAddressType | None = None, - local_port: int | None = None, - tls: bool = False, - ssl_context: ssl.SSLContext | None = None, - tls_standard_compatible: bool = True, - tls_hostname: str | None = None, - happy_eyeballs_delay: float = 0.25, -) -> SocketStream | TLSStream: - """ - Connect to a host using the TCP protocol. - - This function implements the stateless version of the Happy Eyeballs algorithm (RFC - 6555). If ``remote_host`` is a host name that resolves to multiple IP addresses, - each one is tried until one connection attempt succeeds. If the first attempt does - not connected within 250 milliseconds, a second attempt is started using the next - address in the list, and so on. On IPv6 enabled systems, an IPv6 address (if - available) is tried first. - - When the connection has been established, a TLS handshake will be done if either - ``ssl_context`` or ``tls_hostname`` is not ``None``, or if ``tls`` is ``True``. - - :param remote_host: the IP address or host name to connect to - :param remote_port: port on the target host to connect to - :param local_host: the interface address or name to bind the socket to before - connecting - :param local_port: the local port to bind to (requires ``local_host`` to also be - set) - :param tls: ``True`` to do a TLS handshake with the connected stream and return a - :class:`~anyio.streams.tls.TLSStream` instead - :param ssl_context: the SSL context object to use (if omitted, a default context is - created) - :param tls_standard_compatible: If ``True``, performs the TLS shutdown handshake - before closing the stream and requires that the server does this as well. - Otherwise, :exc:`~ssl.SSLEOFError` may be raised during reads from the stream. - Some protocols, such as HTTP, require this option to be ``False``. - See :meth:`~ssl.SSLContext.wrap_socket` for details. - :param tls_hostname: host name to check the server certificate against (defaults to - the value of ``remote_host``) - :param happy_eyeballs_delay: delay (in seconds) before starting the next connection - attempt - :return: a socket stream object if no TLS handshake was done, otherwise a TLS stream - :raises ConnectionFailed: if the connection fails - - """ - # Placed here due to https://github.com/python/mypy/issues/7057 - connected_stream: SocketStream | None = None - - async def try_connect(remote_host: str, event: Event) -> None: - nonlocal connected_stream - try: - stream = await asynclib.connect_tcp(remote_host, remote_port, local_address) - except OSError as exc: - oserrors.append(exc) - return - else: - if connected_stream is None: - connected_stream = stream - tg.cancel_scope.cancel() - else: - await stream.aclose() - finally: - event.set() - - asynclib = get_async_backend() - local_address: IPSockAddrType | None = None - family = socket.AF_UNSPEC - if local_host: - gai_res = await getaddrinfo(str(local_host), local_port) - family, *_, local_address = gai_res[0] - - target_host = str(remote_host) - try: - addr_obj = ip_address(remote_host) - except ValueError: - addr_obj = None - - if addr_obj is not None: - if isinstance(addr_obj, IPv6Address): - target_addrs = [(socket.AF_INET6, addr_obj.compressed)] - else: - target_addrs = [(socket.AF_INET, addr_obj.compressed)] - else: - # getaddrinfo() will raise an exception if name resolution fails - gai_res = await getaddrinfo( - target_host, remote_port, family=family, type=socket.SOCK_STREAM - ) - - # Organize the list so that the first address is an IPv6 address (if available) - # and the second one is an IPv4 addresses. The rest can be in whatever order. - v6_found = v4_found = False - target_addrs = [] - for af, *_, sa in gai_res: - if af == socket.AF_INET6 and not v6_found: - v6_found = True - target_addrs.insert(0, (af, sa[0])) - elif af == socket.AF_INET and not v4_found and v6_found: - v4_found = True - target_addrs.insert(1, (af, sa[0])) - else: - target_addrs.append((af, sa[0])) - - oserrors: list[OSError] = [] - try: - async with create_task_group() as tg: - for _af, addr in target_addrs: - event = Event() - tg.start_soon(try_connect, addr, event) - with move_on_after(happy_eyeballs_delay): - await event.wait() - - if connected_stream is None: - cause = ( - oserrors[0] - if len(oserrors) == 1 - else ExceptionGroup("multiple connection attempts failed", oserrors) - ) - raise OSError("All connection attempts failed") from cause - finally: - oserrors.clear() - - if tls or tls_hostname or ssl_context: - try: - return await TLSStream.wrap( - connected_stream, - server_side=False, - hostname=tls_hostname or str(remote_host), - ssl_context=ssl_context, - standard_compatible=tls_standard_compatible, - ) - except BaseException: - await aclose_forcefully(connected_stream) - raise - - return connected_stream - - -async def connect_unix(path: str | bytes | PathLike[Any]) -> UNIXSocketStream: - """ - Connect to the given UNIX socket. - - Not available on Windows. - - :param path: path to the socket - :return: a socket stream object - :raises ConnectionFailed: if the connection fails - - """ - path = os.fspath(path) - return await get_async_backend().connect_unix(path) - - -async def create_tcp_listener( - *, - local_host: IPAddressType | None = None, - local_port: int = 0, - family: AnyIPAddressFamily = socket.AddressFamily.AF_UNSPEC, - backlog: int = 65536, - reuse_port: bool = False, -) -> MultiListener[SocketStream]: - """ - Create a TCP socket listener. - - :param local_port: port number to listen on - :param local_host: IP address of the interface to listen on. If omitted, listen on - all IPv4 and IPv6 interfaces. To listen on all interfaces on a specific address - family, use ``0.0.0.0`` for IPv4 or ``::`` for IPv6. - :param family: address family (used if ``local_host`` was omitted) - :param backlog: maximum number of queued incoming connections (up to a maximum of - 2**16, or 65536) - :param reuse_port: ``True`` to allow multiple sockets to bind to the same - address/port (not supported on Windows) - :return: a multi-listener object containing one or more socket listeners - :raises OSError: if there's an error creating a socket, or binding to one or more - interfaces failed - - """ - asynclib = get_async_backend() - backlog = min(backlog, 65536) - local_host = str(local_host) if local_host is not None else None - - def setup_raw_socket( - fam: AddressFamily, - bind_addr: tuple[str, int] | tuple[str, int, int, int], - *, - v6only: bool = True, - ) -> socket.socket: - sock = socket.socket(fam) - try: - sock.setblocking(False) - - if fam == AddressFamily.AF_INET6: - sock.setsockopt(IPPROTO_IPV6, socket.IPV6_V6ONLY, v6only) - - # For Windows, enable exclusive address use. For others, enable address - # reuse. - if sys.platform == "win32": - sock.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1) - else: - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - - if reuse_port: - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) - - # Workaround for #554 - if fam == socket.AF_INET6 and "%" in bind_addr[0]: - addr, scope_id = bind_addr[0].split("%", 1) - bind_addr = (addr, bind_addr[1], 0, int(scope_id)) - - sock.bind(bind_addr) - sock.listen(backlog) - except BaseException: - sock.close() - raise - - return sock - - # We passing type=0 on non-Windows platforms as a workaround for a uvloop bug - # where we don't get the correct scope ID for IPv6 link-local addresses when passing - # type=socket.SOCK_STREAM to getaddrinfo(): - # https://github.com/MagicStack/uvloop/issues/539 - gai_res = await getaddrinfo( - local_host, - local_port, - family=family, - type=socket.SOCK_STREAM if sys.platform == "win32" else 0, - flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG, - ) - - # The set comprehension is here to work around a glibc bug: - # https://sourceware.org/bugzilla/show_bug.cgi?id=14969 - sockaddrs = sorted({res for res in gai_res if res[1] == SocketKind.SOCK_STREAM}) - - # Special case for dual-stack binding on the "any" interface - if ( - local_host is None - and family == AddressFamily.AF_UNSPEC - and socket.has_dualstack_ipv6() - and any(fam == AddressFamily.AF_INET6 for fam, *_ in gai_res) - ): - raw_socket = setup_raw_socket( - AddressFamily.AF_INET6, ("::", local_port), v6only=False - ) - listener = asynclib.create_tcp_listener(raw_socket) - return MultiListener([listener]) - - errors: list[OSError] = [] - try: - for _ in range(len(sockaddrs)): - listeners: list[SocketListener] = [] - bound_ephemeral_port = local_port - try: - for fam, *_, sockaddr in sockaddrs: - sockaddr = sockaddr[0], bound_ephemeral_port, *sockaddr[2:] - raw_socket = setup_raw_socket(fam, sockaddr) - - # Store the assigned port if an ephemeral port was requested, so - # we'll bind to the same port on all interfaces - if local_port == 0 and len(gai_res) > 1: - bound_ephemeral_port = raw_socket.getsockname()[1] - - listeners.append(asynclib.create_tcp_listener(raw_socket)) - except BaseException as exc: - for listener in listeners: - await listener.aclose() - - # If an ephemeral port was requested but binding the assigned port - # failed for another interface, rotate the address list and try again - if ( - isinstance(exc, OSError) - and exc.errno == errno.EADDRINUSE - and local_port == 0 - and bound_ephemeral_port - ): - errors.append(exc) - sockaddrs.append(sockaddrs.pop(0)) - continue - - raise - - return MultiListener(listeners) - - raise OSError( - f"Could not create {len(sockaddrs)} listeners with a consistent port" - ) from ExceptionGroup("Several bind attempts failed", errors) - finally: - del errors # Prevent reference cycles - - -async def create_unix_listener( - path: str | bytes | PathLike[Any], - *, - mode: int | None = None, - backlog: int = 65536, -) -> SocketListener: - """ - Create a UNIX socket listener. - - Not available on Windows. - - :param path: path of the socket - :param mode: permissions to set on the socket - :param backlog: maximum number of queued incoming connections (up to a maximum of - 2**16, or 65536) - :return: a listener object - - .. versionchanged:: 3.0 - If a socket already exists on the file system in the given path, it will be - removed first. - - """ - backlog = min(backlog, 65536) - raw_socket = await setup_unix_local_socket(path, mode, socket.SOCK_STREAM) - try: - raw_socket.listen(backlog) - return get_async_backend().create_unix_listener(raw_socket) - except BaseException: - raw_socket.close() - raise - - -async def create_udp_socket( - family: AnyIPAddressFamily = AddressFamily.AF_UNSPEC, - *, - local_host: IPAddressType | None = None, - local_port: int = 0, - reuse_port: bool = False, -) -> UDPSocket: - """ - Create a UDP socket. - - If ``port`` has been given, the socket will be bound to this port on the local - machine, making this socket suitable for providing UDP based services. - - :param family: address family (``AF_INET`` or ``AF_INET6``) – automatically - determined from ``local_host`` if omitted - :param local_host: IP address or host name of the local interface to bind to - :param local_port: local port to bind to - :param reuse_port: ``True`` to allow multiple sockets to bind to the same - address/port (not supported on Windows) - :return: a UDP socket - - """ - if family is AddressFamily.AF_UNSPEC and not local_host: - raise ValueError('Either "family" or "local_host" must be given') - - if local_host: - gai_res = await getaddrinfo( - str(local_host), - local_port, - family=family, - type=socket.SOCK_DGRAM, - flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG, - ) - family = cast(AnyIPAddressFamily, gai_res[0][0]) - local_address = gai_res[0][-1] - elif family is AddressFamily.AF_INET6: - local_address = ("::", 0) - else: - local_address = ("0.0.0.0", 0) - - sock = await get_async_backend().create_udp_socket( - family, local_address, None, reuse_port - ) - return cast(UDPSocket, sock) - - -async def create_connected_udp_socket( - remote_host: IPAddressType, - remote_port: int, - *, - family: AnyIPAddressFamily = AddressFamily.AF_UNSPEC, - local_host: IPAddressType | None = None, - local_port: int = 0, - reuse_port: bool = False, -) -> ConnectedUDPSocket: - """ - Create a connected UDP socket. - - Connected UDP sockets can only communicate with the specified remote host/port, an - any packets sent from other sources are dropped. - - :param remote_host: remote host to set as the default target - :param remote_port: port on the remote host to set as the default target - :param family: address family (``AF_INET`` or ``AF_INET6``) – automatically - determined from ``local_host`` or ``remote_host`` if omitted - :param local_host: IP address or host name of the local interface to bind to - :param local_port: local port to bind to - :param reuse_port: ``True`` to allow multiple sockets to bind to the same - address/port (not supported on Windows) - :return: a connected UDP socket - - """ - local_address = None - if local_host: - gai_res = await getaddrinfo( - str(local_host), - local_port, - family=family, - type=socket.SOCK_DGRAM, - flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG, - ) - family = cast(AnyIPAddressFamily, gai_res[0][0]) - local_address = gai_res[0][-1] - - gai_res = await getaddrinfo( - str(remote_host), remote_port, family=family, type=socket.SOCK_DGRAM - ) - family = cast(AnyIPAddressFamily, gai_res[0][0]) - remote_address = gai_res[0][-1] - - sock = await get_async_backend().create_udp_socket( - family, local_address, remote_address, reuse_port - ) - return cast(ConnectedUDPSocket, sock) - - -async def create_unix_datagram_socket( - *, - local_path: None | str | bytes | PathLike[Any] = None, - local_mode: int | None = None, -) -> UNIXDatagramSocket: - """ - Create a UNIX datagram socket. - - Not available on Windows. - - If ``local_path`` has been given, the socket will be bound to this path, making this - socket suitable for receiving datagrams from other processes. Other processes can - send datagrams to this socket only if ``local_path`` is set. - - If a socket already exists on the file system in the ``local_path``, it will be - removed first. - - :param local_path: the path on which to bind to - :param local_mode: permissions to set on the local socket - :return: a UNIX datagram socket - - """ - raw_socket = await setup_unix_local_socket( - local_path, local_mode, socket.SOCK_DGRAM - ) - return await get_async_backend().create_unix_datagram_socket(raw_socket, None) - - -async def create_connected_unix_datagram_socket( - remote_path: str | bytes | PathLike[Any], - *, - local_path: None | str | bytes | PathLike[Any] = None, - local_mode: int | None = None, -) -> ConnectedUNIXDatagramSocket: - """ - Create a connected UNIX datagram socket. - - Connected datagram sockets can only communicate with the specified remote path. - - If ``local_path`` has been given, the socket will be bound to this path, making - this socket suitable for receiving datagrams from other processes. Other processes - can send datagrams to this socket only if ``local_path`` is set. - - If a socket already exists on the file system in the ``local_path``, it will be - removed first. - - :param remote_path: the path to set as the default target - :param local_path: the path on which to bind to - :param local_mode: permissions to set on the local socket - :return: a connected UNIX datagram socket - - """ - remote_path = os.fspath(remote_path) - raw_socket = await setup_unix_local_socket( - local_path, local_mode, socket.SOCK_DGRAM - ) - return await get_async_backend().create_unix_datagram_socket( - raw_socket, remote_path - ) - - -async def getaddrinfo( - host: bytes | str | None, - port: str | int | None, - *, - family: int | AddressFamily = 0, - type: int | SocketKind = 0, - proto: int = 0, - flags: int = 0, -) -> list[tuple[AddressFamily, SocketKind, int, str, tuple[str, int]]]: - """ - Look up a numeric IP address given a host name. - - Internationalized domain names are translated according to the (non-transitional) - IDNA 2008 standard. - - .. note:: 4-tuple IPv6 socket addresses are automatically converted to 2-tuples of - (host, port), unlike what :func:`socket.getaddrinfo` does. - - :param host: host name - :param port: port number - :param family: socket family (`'AF_INET``, ...) - :param type: socket type (``SOCK_STREAM``, ...) - :param proto: protocol number - :param flags: flags to pass to upstream ``getaddrinfo()`` - :return: list of tuples containing (family, type, proto, canonname, sockaddr) - - .. seealso:: :func:`socket.getaddrinfo` - - """ - # Handle unicode hostnames - if isinstance(host, str): - try: - encoded_host: bytes | None = host.encode("ascii") - except UnicodeEncodeError: - import idna - - encoded_host = idna.encode(host, uts46=True) - else: - encoded_host = host - - gai_res = await get_async_backend().getaddrinfo( - encoded_host, port, family=family, type=type, proto=proto, flags=flags - ) - return [ - (family, type, proto, canonname, convert_ipv6_sockaddr(sockaddr)) - for family, type, proto, canonname, sockaddr in gai_res - # filter out IPv6 results when IPv6 is disabled - if not isinstance(sockaddr[0], int) - ] - - -def getnameinfo(sockaddr: IPSockAddrType, flags: int = 0) -> Awaitable[tuple[str, str]]: - """ - Look up the host name of an IP address. - - :param sockaddr: socket address (e.g. (ipaddress, port) for IPv4) - :param flags: flags to pass to upstream ``getnameinfo()`` - :return: a tuple of (host name, service name) - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - .. seealso:: :func:`socket.getnameinfo` - - """ - return get_async_backend().getnameinfo(sockaddr, flags) - - -@deprecated("This function is deprecated; use `wait_readable` instead") -def wait_socket_readable(sock: socket.socket) -> Awaitable[None]: - """ - .. deprecated:: 4.7.0 - Use :func:`wait_readable` instead. - - Wait until the given socket has data to be read. - - .. warning:: Only use this on raw sockets that have not been wrapped by any higher - level constructs like socket streams! - - :param sock: a socket object - :raises ~anyio.ClosedResourceError: if the socket was closed while waiting for the - socket to become readable - :raises ~anyio.BusyResourceError: if another task is already waiting for the socket - to become readable - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().wait_readable(sock.fileno()) - - -@deprecated("This function is deprecated; use `wait_writable` instead") -def wait_socket_writable(sock: socket.socket) -> Awaitable[None]: - """ - .. deprecated:: 4.7.0 - Use :func:`wait_writable` instead. - - Wait until the given socket can be written to. - - This does **NOT** work on Windows when using the asyncio backend with a proactor - event loop (default on py3.8+). - - .. warning:: Only use this on raw sockets that have not been wrapped by any higher - level constructs like socket streams! - - :param sock: a socket object - :raises ~anyio.ClosedResourceError: if the socket was closed while waiting for the - socket to become writable - :raises ~anyio.BusyResourceError: if another task is already waiting for the socket - to become writable - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().wait_writable(sock.fileno()) - - -def wait_readable(obj: FileDescriptorLike) -> Awaitable[None]: - """ - Wait until the given object has data to be read. - - On Unix systems, ``obj`` must either be an integer file descriptor, or else an - object with a ``.fileno()`` method which returns an integer file descriptor. Any - kind of file descriptor can be passed, though the exact semantics will depend on - your kernel. For example, this probably won't do anything useful for on-disk files. - - On Windows systems, ``obj`` must either be an integer ``SOCKET`` handle, or else an - object with a ``.fileno()`` method which returns an integer ``SOCKET`` handle. File - descriptors aren't supported, and neither are handles that refer to anything besides - a ``SOCKET``. - - On backends where this functionality is not natively provided (asyncio - ``ProactorEventLoop`` on Windows), it is provided using a separate selector thread - which is set to shut down when the interpreter shuts down. - - .. warning:: Don't use this on raw sockets that have been wrapped by any higher - level constructs like socket streams! - - :param obj: an object with a ``.fileno()`` method or an integer handle - :raises ~anyio.ClosedResourceError: if the object was closed while waiting for the - object to become readable - :raises ~anyio.BusyResourceError: if another task is already waiting for the object - to become readable - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().wait_readable(obj) - - -def wait_writable(obj: FileDescriptorLike) -> Awaitable[None]: - """ - Wait until the given object can be written to. - - :param obj: an object with a ``.fileno()`` method or an integer handle - :raises ~anyio.ClosedResourceError: if the object was closed while waiting for the - object to become writable - :raises ~anyio.BusyResourceError: if another task is already waiting for the object - to become writable - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - .. seealso:: See the documentation of :func:`wait_readable` for the definition of - ``obj`` and notes on backend compatibility. - - .. warning:: Don't use this on raw sockets that have been wrapped by any higher - level constructs like socket streams! - - """ - return get_async_backend().wait_writable(obj) - - -def notify_closing(obj: FileDescriptorLike) -> None: - """ - Call this before closing a file descriptor (on Unix) or socket (on - Windows). This will cause any `wait_readable` or `wait_writable` - calls on the given object to immediately wake up and raise - `~anyio.ClosedResourceError`. - - This doesn't actually close the object – you still have to do that - yourself afterwards. Also, you want to be careful to make sure no - new tasks start waiting on the object in between when you call this - and when it's actually closed. So to close something properly, you - usually want to do these steps in order: - - 1. Explicitly mark the object as closed, so that any new attempts - to use it will abort before they start. - 2. Call `notify_closing` to wake up any already-existing users. - 3. Actually close the object. - - It's also possible to do them in a different order if that's more - convenient, *but only if* you make sure not to have any checkpoints in - between the steps. This way they all happen in a single atomic - step, so other tasks won't be able to tell what order they happened - in anyway. - - :param obj: an object with a ``.fileno()`` method or an integer handle - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - get_async_backend().notify_closing(obj) - - -# -# Private API -# - - -def convert_ipv6_sockaddr( - sockaddr: tuple[str, int, int, int] | tuple[str, int], -) -> tuple[str, int]: - """ - Convert a 4-tuple IPv6 socket address to a 2-tuple (address, port) format. - - If the scope ID is nonzero, it is added to the address, separated with ``%``. - Otherwise the flow id and scope id are simply cut off from the tuple. - Any other kinds of socket addresses are returned as-is. - - :param sockaddr: the result of :meth:`~socket.socket.getsockname` - :return: the converted socket address - - """ - # This is more complicated than it should be because of MyPy - if isinstance(sockaddr, tuple) and len(sockaddr) == 4: - host, port, flowinfo, scope_id = sockaddr - if scope_id: - # PyPy (as of v7.3.11) leaves the interface name in the result, so - # we discard it and only get the scope ID from the end - # (https://foss.heptapod.net/pypy/pypy/-/issues/3938) - host = host.split("%")[0] - - # Add scope_id to the address - return f"{host}%{scope_id}", port - else: - return host, port - else: - return sockaddr - - -async def setup_unix_local_socket( - path: None | str | bytes | PathLike[Any], - mode: int | None, - socktype: int, -) -> socket.socket: - """ - Create a UNIX local socket object, deleting the socket at the given path if it - exists. - - Not available on Windows. - - :param path: path of the socket - :param mode: permissions to set on the socket - :param socktype: socket.SOCK_STREAM or socket.SOCK_DGRAM - - """ - path_str: str | None - if path is not None: - path_str = os.fsdecode(path) - - # Linux abstract namespace sockets aren't backed by a concrete file so skip stat call - if not path_str.startswith("\0"): - # Copied from pathlib... - try: - stat_result = os.stat(path) - except OSError as e: - if e.errno not in ( - errno.ENOENT, - errno.ENOTDIR, - errno.EBADF, - errno.ELOOP, - ): - raise - else: - if stat.S_ISSOCK(stat_result.st_mode): - os.unlink(path) - else: - path_str = None - - raw_socket = socket.socket(socket.AF_UNIX, socktype) - raw_socket.setblocking(False) - - if path_str is not None: - try: - await to_thread.run_sync(raw_socket.bind, path_str, abandon_on_cancel=True) - if mode is not None: - await to_thread.run_sync(chmod, path_str, mode, abandon_on_cancel=True) - except BaseException: - raw_socket.close() - raise - - return raw_socket - - -@dataclass -class TCPConnectable(ByteStreamConnectable): - """ - Connects to a TCP server at the given host and port. - - :param host: host name or IP address of the server - :param port: TCP port number of the server - """ - - host: str | IPv4Address | IPv6Address - port: int - - def __post_init__(self) -> None: - if self.port < 1 or self.port > 65535: - raise ValueError("TCP port number out of range") - - @override - async def connect(self) -> SocketStream: - try: - return await connect_tcp(self.host, self.port) - except OSError as exc: - raise ConnectionFailed( - f"error connecting to {self.host}:{self.port}: {exc}" - ) from exc - - -@dataclass -class UNIXConnectable(ByteStreamConnectable): - """ - Connects to a UNIX domain socket at the given path. - - :param path: the file system path of the socket - """ - - path: str | bytes | PathLike[str] | PathLike[bytes] - - @override - async def connect(self) -> UNIXSocketStream: - try: - return await connect_unix(self.path) - except OSError as exc: - raise ConnectionFailed(f"error connecting to {self.path!r}: {exc}") from exc - - -def as_connectable( - remote: ByteStreamConnectable - | tuple[str | IPv4Address | IPv6Address, int] - | str - | bytes - | PathLike[str], - /, - *, - tls: bool = False, - ssl_context: ssl.SSLContext | None = None, - tls_hostname: str | None = None, - tls_standard_compatible: bool = True, -) -> ByteStreamConnectable: - """ - Return a byte stream connectable from the given object. - - If a bytestream connectable is given, it is returned unchanged. - If a tuple of (host, port) is given, a TCP connectable is returned. - If a string or bytes path is given, a UNIX connectable is returned. - - If ``tls=True``, the connectable will be wrapped in a - :class:`~.streams.tls.TLSConnectable`. - - :param remote: a connectable, a tuple of (host, port) or a path to a UNIX socket - :param tls: if ``True``, wrap the plaintext connectable in a - :class:`~.streams.tls.TLSConnectable`, using the provided TLS settings) - :param ssl_context: if ``tls=True``, the SSLContext object to use (if not provided, - a secure default will be created) - :param tls_hostname: if ``tls=True``, host name of the server to use for checking - the server certificate (defaults to the host portion of the address for TCP - connectables) - :param tls_standard_compatible: if ``False`` and ``tls=True``, makes the TLS stream - skip the closing handshake when closing the connection, so it won't raise an - exception if the server does the same - - """ - connectable: TCPConnectable | UNIXConnectable | TLSConnectable - if isinstance(remote, ByteStreamConnectable): - return remote - elif isinstance(remote, tuple) and len(remote) == 2: - connectable = TCPConnectable(*remote) - elif isinstance(remote, (str, bytes, PathLike)): - connectable = UNIXConnectable(remote) - else: - raise TypeError(f"cannot convert {remote!r} to a connectable") - - if tls: - if not tls_hostname and isinstance(connectable, TCPConnectable): - tls_hostname = str(connectable.host) - - connectable = TLSConnectable( - connectable, - ssl_context=ssl_context, - hostname=tls_hostname, - standard_compatible=tls_standard_compatible, - ) - - return connectable diff --git a/server/venv/Lib/site-packages/anyio/_core/_streams.py b/server/venv/Lib/site-packages/anyio/_core/_streams.py deleted file mode 100644 index 2b9c7df..0000000 --- a/server/venv/Lib/site-packages/anyio/_core/_streams.py +++ /dev/null @@ -1,52 +0,0 @@ -from __future__ import annotations - -import math -from typing import TypeVar -from warnings import warn - -from ..streams.memory import ( - MemoryObjectReceiveStream, - MemoryObjectSendStream, - _MemoryObjectStreamState, -) - -T_Item = TypeVar("T_Item") - - -class create_memory_object_stream( - tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]], -): - """ - Create a memory object stream. - - The stream's item type can be annotated like - :func:`create_memory_object_stream[T_Item]`. - - :param max_buffer_size: number of items held in the buffer until ``send()`` starts - blocking - :param item_type: old way of marking the streams with the right generic type for - static typing (does nothing on AnyIO 4) - - .. deprecated:: 4.0 - Use ``create_memory_object_stream[YourItemType](...)`` instead. - :return: a tuple of (send stream, receive stream) - - """ - - def __new__( # type: ignore[misc] - cls, max_buffer_size: float = 0, item_type: object = None - ) -> tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]]: - if max_buffer_size != math.inf and not isinstance(max_buffer_size, int): - raise ValueError("max_buffer_size must be either an integer or math.inf") - if max_buffer_size < 0: - raise ValueError("max_buffer_size cannot be negative") - if item_type is not None: - warn( - "The item_type argument has been deprecated in AnyIO 4.0. " - "Use create_memory_object_stream[YourItemType](...) instead.", - DeprecationWarning, - stacklevel=2, - ) - - state = _MemoryObjectStreamState[T_Item](max_buffer_size) - return (MemoryObjectSendStream(state), MemoryObjectReceiveStream(state)) diff --git a/server/venv/Lib/site-packages/anyio/_core/_subprocesses.py b/server/venv/Lib/site-packages/anyio/_core/_subprocesses.py deleted file mode 100644 index 9796f8b..0000000 --- a/server/venv/Lib/site-packages/anyio/_core/_subprocesses.py +++ /dev/null @@ -1,196 +0,0 @@ -from __future__ import annotations - -from collections.abc import AsyncIterable, Iterable, Mapping, Sequence -from io import BytesIO -from os import PathLike -from subprocess import PIPE, CalledProcessError, CompletedProcess -from typing import IO, Any, TypeAlias, cast - -from ..abc import Process -from ._eventloop import get_async_backend -from ._tasks import create_task_group - -StrOrBytesPath: TypeAlias = str | bytes | PathLike[str] | PathLike[bytes] - - -async def run_process( - command: StrOrBytesPath | Sequence[StrOrBytesPath], - *, - input: bytes | None = None, - stdin: int | IO[Any] | None = None, - stdout: int | IO[Any] | None = PIPE, - stderr: int | IO[Any] | None = PIPE, - check: bool = True, - cwd: StrOrBytesPath | None = None, - env: Mapping[str, str] | None = None, - startupinfo: Any = None, - creationflags: int = 0, - start_new_session: bool = False, - pass_fds: Sequence[int] = (), - user: str | int | None = None, - group: str | int | None = None, - extra_groups: Iterable[str | int] | None = None, - umask: int = -1, -) -> CompletedProcess[bytes]: - """ - Run an external command in a subprocess and wait until it completes. - - .. seealso:: :func:`subprocess.run` - - :param command: either a string to pass to the shell, or an iterable of strings - containing the executable name or path and its arguments - :param input: bytes passed to the standard input of the subprocess - :param stdin: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, - a file-like object, or `None`; ``input`` overrides this - :param stdout: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, - a file-like object, or `None` - :param stderr: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, - :data:`subprocess.STDOUT`, a file-like object, or `None` - :param check: if ``True``, raise :exc:`~subprocess.CalledProcessError` if the - process terminates with a return code other than 0 - :param cwd: If not ``None``, change the working directory to this before running the - command - :param env: if not ``None``, this mapping replaces the inherited environment - variables from the parent process - :param startupinfo: an instance of :class:`subprocess.STARTUPINFO` that can be used - to specify process startup parameters (Windows only) - :param creationflags: flags that can be used to control the creation of the - subprocess (see :class:`subprocess.Popen` for the specifics) - :param start_new_session: if ``true`` the setsid() system call will be made in the - child process prior to the execution of the subprocess. (POSIX only) - :param pass_fds: sequence of file descriptors to keep open between the parent and - child processes. (POSIX only) - :param user: effective user to run the process as (Python >= 3.9, POSIX only) - :param group: effective group to run the process as (Python >= 3.9, POSIX only) - :param extra_groups: supplementary groups to set in the subprocess (Python >= 3.9, - POSIX only) - :param umask: if not negative, this umask is applied in the child process before - running the given command (Python >= 3.9, POSIX only) - :return: an object representing the completed process - :raises ~subprocess.CalledProcessError: if ``check`` is ``True`` and the process - exits with a nonzero return code - - """ - - async def drain_stream(stream: AsyncIterable[bytes], index: int) -> None: - buffer = BytesIO() - async for chunk in stream: - buffer.write(chunk) - - stream_contents[index] = buffer.getvalue() - - if stdin is not None and input is not None: - raise ValueError("only one of stdin and input is allowed") - - async with await open_process( - command, - stdin=PIPE if input else stdin, - stdout=stdout, - stderr=stderr, - cwd=cwd, - env=env, - startupinfo=startupinfo, - creationflags=creationflags, - start_new_session=start_new_session, - pass_fds=pass_fds, - user=user, - group=group, - extra_groups=extra_groups, - umask=umask, - ) as process: - stream_contents: list[bytes | None] = [None, None] - async with create_task_group() as tg: - if process.stdout: - tg.start_soon(drain_stream, process.stdout, 0) - - if process.stderr: - tg.start_soon(drain_stream, process.stderr, 1) - - if process.stdin and input: - await process.stdin.send(input) - await process.stdin.aclose() - - await process.wait() - - output, errors = stream_contents - if check and process.returncode != 0: - raise CalledProcessError(cast(int, process.returncode), command, output, errors) - - return CompletedProcess(command, cast(int, process.returncode), output, errors) - - -async def open_process( - command: StrOrBytesPath | Sequence[StrOrBytesPath], - *, - stdin: int | IO[Any] | None = PIPE, - stdout: int | IO[Any] | None = PIPE, - stderr: int | IO[Any] | None = PIPE, - cwd: StrOrBytesPath | None = None, - env: Mapping[str, str] | None = None, - startupinfo: Any = None, - creationflags: int = 0, - start_new_session: bool = False, - pass_fds: Sequence[int] = (), - user: str | int | None = None, - group: str | int | None = None, - extra_groups: Iterable[str | int] | None = None, - umask: int = -1, -) -> Process: - """ - Start an external command in a subprocess. - - .. seealso:: :class:`subprocess.Popen` - - :param command: either a string to pass to the shell, or an iterable of strings - containing the executable name or path and its arguments - :param stdin: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, a - file-like object, or ``None`` - :param stdout: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, - a file-like object, or ``None`` - :param stderr: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, - :data:`subprocess.STDOUT`, a file-like object, or ``None`` - :param cwd: If not ``None``, the working directory is changed before executing - :param env: If env is not ``None``, it must be a mapping that defines the - environment variables for the new process - :param creationflags: flags that can be used to control the creation of the - subprocess (see :class:`subprocess.Popen` for the specifics) - :param startupinfo: an instance of :class:`subprocess.STARTUPINFO` that can be used - to specify process startup parameters (Windows only) - :param start_new_session: if ``true`` the setsid() system call will be made in the - child process prior to the execution of the subprocess. (POSIX only) - :param pass_fds: sequence of file descriptors to keep open between the parent and - child processes. (POSIX only) - :param user: effective user to run the process as (POSIX only) - :param group: effective group to run the process as (POSIX only) - :param extra_groups: supplementary groups to set in the subprocess (POSIX only) - :param umask: if not negative, this umask is applied in the child process before - running the given command (POSIX only) - :return: an asynchronous process object - - """ - kwargs: dict[str, Any] = {} - if user is not None: - kwargs["user"] = user - - if group is not None: - kwargs["group"] = group - - if extra_groups is not None: - kwargs["extra_groups"] = group - - if umask >= 0: - kwargs["umask"] = umask - - return await get_async_backend().open_process( - command, - stdin=stdin, - stdout=stdout, - stderr=stderr, - cwd=cwd, - env=env, - startupinfo=startupinfo, - creationflags=creationflags, - start_new_session=start_new_session, - pass_fds=pass_fds, - **kwargs, - ) diff --git a/server/venv/Lib/site-packages/anyio/_core/_synchronization.py b/server/venv/Lib/site-packages/anyio/_core/_synchronization.py deleted file mode 100644 index ed19116..0000000 --- a/server/venv/Lib/site-packages/anyio/_core/_synchronization.py +++ /dev/null @@ -1,772 +0,0 @@ -from __future__ import annotations - -import math -from collections import deque -from collections.abc import Callable -from dataclasses import dataclass -from types import TracebackType -from typing import TypeVar - -from ..lowlevel import checkpoint_if_cancelled -from ._eventloop import get_async_backend -from ._exceptions import BusyResourceError, NoEventLoopError -from ._tasks import CancelScope -from ._testing import TaskInfo, get_current_task - -T = TypeVar("T") - - -@dataclass(frozen=True) -class EventStatistics: - """ - :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Event.wait` - """ - - tasks_waiting: int - - -@dataclass(frozen=True) -class CapacityLimiterStatistics: - """ - :ivar int borrowed_tokens: number of tokens currently borrowed by tasks - :ivar float total_tokens: total number of available tokens - :ivar tuple borrowers: tasks or other objects currently holding tokens borrowed from - this limiter - :ivar int tasks_waiting: number of tasks waiting on - :meth:`~.CapacityLimiter.acquire` or - :meth:`~.CapacityLimiter.acquire_on_behalf_of` - """ - - borrowed_tokens: int - total_tokens: float - borrowers: tuple[object, ...] - tasks_waiting: int - - -@dataclass(frozen=True) -class LockStatistics: - """ - :ivar bool locked: flag indicating if this lock is locked or not - :ivar ~anyio.TaskInfo owner: task currently holding the lock (or ``None`` if the - lock is not held by any task) - :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Lock.acquire` - """ - - locked: bool - owner: TaskInfo | None - tasks_waiting: int - - -@dataclass(frozen=True) -class ConditionStatistics: - """ - :ivar int tasks_waiting: number of tasks blocked on :meth:`~.Condition.wait` - :ivar ~anyio.LockStatistics lock_statistics: statistics of the underlying - :class:`~.Lock` - """ - - tasks_waiting: int - lock_statistics: LockStatistics - - -@dataclass(frozen=True) -class SemaphoreStatistics: - """ - :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Semaphore.acquire` - - """ - - tasks_waiting: int - - -class Event: - __slots__ = ("__weakref__",) - - def __new__(cls) -> Event: - try: - return get_async_backend().create_event() - except NoEventLoopError: - return EventAdapter() - - def set(self) -> None: - """Set the flag, notifying all listeners.""" - raise NotImplementedError - - def is_set(self) -> bool: - """Return ``True`` if the flag is set, ``False`` if not.""" - raise NotImplementedError - - async def wait(self) -> None: - """ - Wait until the flag has been set. - - If the flag has already been set when this method is called, it returns - immediately. - - """ - raise NotImplementedError - - def statistics(self) -> EventStatistics: - """Return statistics about the current state of this event.""" - raise NotImplementedError - - -class EventAdapter(Event): - __slots__ = "_internal_event", "_is_set" - - def __new__(cls) -> EventAdapter: - return object.__new__(cls) - - def __init__(self) -> None: - self._internal_event: Event | None = None - self._is_set = False - - @property - def _event(self) -> Event: - if self._internal_event is None: - self._internal_event = get_async_backend().create_event() - if self._is_set: - self._internal_event.set() - - return self._internal_event - - def set(self) -> None: - if self._internal_event is None: - self._is_set = True - else: - self._event.set() - - def is_set(self) -> bool: - if self._internal_event is None: - return self._is_set - - return self._internal_event.is_set() - - async def wait(self) -> None: - await self._event.wait() - - def statistics(self) -> EventStatistics: - if self._internal_event is None: - return EventStatistics(tasks_waiting=0) - - return self._internal_event.statistics() - - -class Lock: - __slots__ = ("__weakref__",) - - def __new__(cls, *, fast_acquire: bool = False) -> Lock: - try: - return get_async_backend().create_lock(fast_acquire=fast_acquire) - except NoEventLoopError: - return LockAdapter(fast_acquire=fast_acquire) - - async def __aenter__(self) -> None: - await self.acquire() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.release() - - async def acquire(self) -> None: - """Acquire the lock.""" - raise NotImplementedError - - def acquire_nowait(self) -> None: - """ - Acquire the lock, without blocking. - - :raises ~anyio.WouldBlock: if the operation would block - - """ - raise NotImplementedError - - def release(self) -> None: - """Release the lock.""" - raise NotImplementedError - - def locked(self) -> bool: - """Return True if the lock is currently held.""" - raise NotImplementedError - - def statistics(self) -> LockStatistics: - """ - Return statistics about the current state of this lock. - - .. versionadded:: 3.0 - """ - raise NotImplementedError - - -class LockAdapter(Lock): - __slots__ = "_internal_lock", "_fast_acquire" - - def __new__(cls, *, fast_acquire: bool = False) -> LockAdapter: - return object.__new__(cls) - - def __init__(self, *, fast_acquire: bool = False): - self._internal_lock: Lock | None = None - self._fast_acquire = fast_acquire - - @property - def _lock(self) -> Lock: - if self._internal_lock is None: - self._internal_lock = get_async_backend().create_lock( - fast_acquire=self._fast_acquire - ) - - return self._internal_lock - - async def __aenter__(self) -> None: - await self._lock.acquire() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - if self._internal_lock is not None: - self._internal_lock.release() - - async def acquire(self) -> None: - """Acquire the lock.""" - await self._lock.acquire() - - def acquire_nowait(self) -> None: - """ - Acquire the lock, without blocking. - - :raises ~anyio.WouldBlock: if the operation would block - - """ - self._lock.acquire_nowait() - - def release(self) -> None: - """Release the lock.""" - self._lock.release() - - def locked(self) -> bool: - """Return True if the lock is currently held.""" - return self._lock.locked() - - def statistics(self) -> LockStatistics: - """ - Return statistics about the current state of this lock. - - .. versionadded:: 3.0 - - """ - if self._internal_lock is None: - return LockStatistics(False, None, 0) - - return self._internal_lock.statistics() - - -class Condition: - __slots__ = "__weakref__", "_owner_task", "_lock", "_waiters" - - def __init__(self, lock: Lock | None = None): - self._owner_task: TaskInfo | None = None - self._lock = lock or Lock() - self._waiters: deque[Event] = deque() - - async def __aenter__(self) -> None: - await self.acquire() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.release() - - def _check_acquired(self) -> None: - if self._owner_task != get_current_task(): - raise RuntimeError("The current task is not holding the underlying lock") - - async def acquire(self) -> None: - """Acquire the underlying lock.""" - await self._lock.acquire() - self._owner_task = get_current_task() - - def acquire_nowait(self) -> None: - """ - Acquire the underlying lock, without blocking. - - :raises ~anyio.WouldBlock: if the operation would block - - """ - self._lock.acquire_nowait() - self._owner_task = get_current_task() - - def release(self) -> None: - """Release the underlying lock.""" - self._lock.release() - - def locked(self) -> bool: - """Return True if the lock is set.""" - return self._lock.locked() - - def notify(self, n: int = 1) -> None: - """Notify exactly n listeners.""" - self._check_acquired() - for _ in range(n): - try: - event = self._waiters.popleft() - except IndexError: - break - - event.set() - - def notify_all(self) -> None: - """Notify all the listeners.""" - self._check_acquired() - for event in self._waiters: - event.set() - - self._waiters.clear() - - async def wait(self) -> None: - """Wait for a notification.""" - await checkpoint_if_cancelled() - self._check_acquired() - event = Event() - self._waiters.append(event) - self.release() - try: - await event.wait() - except BaseException: - if not event.is_set(): - self._waiters.remove(event) - elif self._waiters: - # This task was notified by could not act on it, so pass - # it on to the next task - self._waiters.popleft().set() - - raise - finally: - with CancelScope(shield=True): - await self.acquire() - - async def wait_for(self, predicate: Callable[[], T]) -> T: - """ - Wait until a predicate becomes true. - - :param predicate: a callable that returns a truthy value when the condition is - met - :return: the result of the predicate - - .. versionadded:: 4.11.0 - - """ - while not (result := predicate()): - await self.wait() - - return result - - def statistics(self) -> ConditionStatistics: - """ - Return statistics about the current state of this condition. - - .. versionadded:: 3.0 - """ - return ConditionStatistics(len(self._waiters), self._lock.statistics()) - - -class Semaphore: - __slots__ = "__weakref__", "_fast_acquire" - - def __new__( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> Semaphore: - try: - return get_async_backend().create_semaphore( - initial_value, max_value=max_value, fast_acquire=fast_acquire - ) - except NoEventLoopError: - return SemaphoreAdapter(initial_value, max_value=max_value) - - def __init__( - self, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ): - if not isinstance(initial_value, int): - raise TypeError("initial_value must be an integer") - if initial_value < 0: - raise ValueError("initial_value must be >= 0") - if max_value is not None: - if not isinstance(max_value, int): - raise TypeError("max_value must be an integer or None") - if max_value < initial_value: - raise ValueError( - "max_value must be equal to or higher than initial_value" - ) - - self._fast_acquire = fast_acquire - - async def __aenter__(self) -> Semaphore: - await self.acquire() - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.release() - - async def acquire(self) -> None: - """Decrement the semaphore value, blocking if necessary.""" - raise NotImplementedError - - def acquire_nowait(self) -> None: - """ - Acquire the underlying lock, without blocking. - - :raises ~anyio.WouldBlock: if the operation would block - - """ - raise NotImplementedError - - def release(self) -> None: - """Increment the semaphore value.""" - raise NotImplementedError - - @property - def value(self) -> int: - """The current value of the semaphore.""" - raise NotImplementedError - - @property - def max_value(self) -> int | None: - """The maximum value of the semaphore.""" - raise NotImplementedError - - def statistics(self) -> SemaphoreStatistics: - """ - Return statistics about the current state of this semaphore. - - .. versionadded:: 3.0 - """ - raise NotImplementedError - - -class SemaphoreAdapter(Semaphore): - __slots__ = "_internal_semaphore", "_initial_value", "_max_value" - - def __new__( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> SemaphoreAdapter: - return object.__new__(cls) - - def __init__( - self, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> None: - super().__init__(initial_value, max_value=max_value, fast_acquire=fast_acquire) - self._internal_semaphore: Semaphore | None = None - self._initial_value = initial_value - self._max_value = max_value - - @property - def _semaphore(self) -> Semaphore: - if self._internal_semaphore is None: - self._internal_semaphore = get_async_backend().create_semaphore( - self._initial_value, max_value=self._max_value - ) - - return self._internal_semaphore - - async def acquire(self) -> None: - await self._semaphore.acquire() - - def acquire_nowait(self) -> None: - self._semaphore.acquire_nowait() - - def release(self) -> None: - self._semaphore.release() - - @property - def value(self) -> int: - if self._internal_semaphore is None: - return self._initial_value - - return self._semaphore.value - - @property - def max_value(self) -> int | None: - return self._max_value - - def statistics(self) -> SemaphoreStatistics: - if self._internal_semaphore is None: - return SemaphoreStatistics(tasks_waiting=0) - - return self._semaphore.statistics() - - -class CapacityLimiter: - __slots__ = ("__weakref__",) - - def __new__(cls, total_tokens: float) -> CapacityLimiter: - try: - return get_async_backend().create_capacity_limiter(total_tokens) - except NoEventLoopError: - return CapacityLimiterAdapter(total_tokens) - - async def __aenter__(self) -> None: - raise NotImplementedError - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - raise NotImplementedError - - @property - def total_tokens(self) -> float: - """ - The total number of tokens available for borrowing. - - This is a read-write property. If the total number of tokens is increased, the - proportionate number of tasks waiting on this limiter will be granted their - tokens. - - .. versionchanged:: 3.0 - The property is now writable. - .. versionchanged:: 4.12 - The value can now be set to 0. - - """ - raise NotImplementedError - - @total_tokens.setter - def total_tokens(self, value: float) -> None: - raise NotImplementedError - - @property - def borrowed_tokens(self) -> int: - """The number of tokens that have currently been borrowed.""" - raise NotImplementedError - - @property - def available_tokens(self) -> float: - """The number of tokens currently available to be borrowed""" - raise NotImplementedError - - def acquire_nowait(self) -> None: - """ - Acquire a token for the current task without waiting for one to become - available. - - :raises ~anyio.WouldBlock: if there are no tokens available for borrowing - - """ - raise NotImplementedError - - def acquire_on_behalf_of_nowait(self, borrower: object) -> None: - """ - Acquire a token without waiting for one to become available. - - :param borrower: the entity borrowing a token - :raises ~anyio.WouldBlock: if there are no tokens available for borrowing - - """ - raise NotImplementedError - - async def acquire(self) -> None: - """ - Acquire a token for the current task, waiting if necessary for one to become - available. - - """ - raise NotImplementedError - - async def acquire_on_behalf_of(self, borrower: object) -> None: - """ - Acquire a token, waiting if necessary for one to become available. - - :param borrower: the entity borrowing a token - - """ - raise NotImplementedError - - def release(self) -> None: - """ - Release the token held by the current task. - - :raises RuntimeError: if the current task has not borrowed a token from this - limiter. - - """ - raise NotImplementedError - - def release_on_behalf_of(self, borrower: object) -> None: - """ - Release the token held by the given borrower. - - :raises RuntimeError: if the borrower has not borrowed a token from this - limiter. - - """ - raise NotImplementedError - - def statistics(self) -> CapacityLimiterStatistics: - """ - Return statistics about the current state of this limiter. - - .. versionadded:: 3.0 - - """ - raise NotImplementedError - - -class CapacityLimiterAdapter(CapacityLimiter): - __slots__ = "_internal_limiter", "_total_tokens" - - def __new__(cls, total_tokens: float) -> CapacityLimiterAdapter: - return object.__new__(cls) - - def __init__(self, total_tokens: float) -> None: - self._internal_limiter: CapacityLimiter | None = None - self.total_tokens = total_tokens - - @property - def _limiter(self) -> CapacityLimiter: - if self._internal_limiter is None: - self._internal_limiter = get_async_backend().create_capacity_limiter( - self._total_tokens - ) - - return self._internal_limiter - - async def __aenter__(self) -> None: - await self._limiter.__aenter__() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - return await self._limiter.__aexit__(exc_type, exc_val, exc_tb) - - @property - def total_tokens(self) -> float: - if self._internal_limiter is None: - return self._total_tokens - - return self._internal_limiter.total_tokens - - @total_tokens.setter - def total_tokens(self, value: float) -> None: - if not isinstance(value, int) and value is not math.inf: - raise TypeError("total_tokens must be an int or math.inf") - elif value < 1: - raise ValueError("total_tokens must be >= 1") - - if self._internal_limiter is None: - self._total_tokens = value - return - - self._limiter.total_tokens = value - - @property - def borrowed_tokens(self) -> int: - if self._internal_limiter is None: - return 0 - - return self._internal_limiter.borrowed_tokens - - @property - def available_tokens(self) -> float: - if self._internal_limiter is None: - return self._total_tokens - - return self._internal_limiter.available_tokens - - def acquire_nowait(self) -> None: - self._limiter.acquire_nowait() - - def acquire_on_behalf_of_nowait(self, borrower: object) -> None: - self._limiter.acquire_on_behalf_of_nowait(borrower) - - async def acquire(self) -> None: - await self._limiter.acquire() - - async def acquire_on_behalf_of(self, borrower: object) -> None: - await self._limiter.acquire_on_behalf_of(borrower) - - def release(self) -> None: - self._limiter.release() - - def release_on_behalf_of(self, borrower: object) -> None: - self._limiter.release_on_behalf_of(borrower) - - def statistics(self) -> CapacityLimiterStatistics: - if self._internal_limiter is None: - return CapacityLimiterStatistics( - borrowed_tokens=0, - total_tokens=self.total_tokens, - borrowers=(), - tasks_waiting=0, - ) - - return self._internal_limiter.statistics() - - -class ResourceGuard: - """ - A context manager for ensuring that a resource is only used by a single task at a - time. - - Entering this context manager while the previous has not exited it yet will trigger - :exc:`BusyResourceError`. - - :param action: the action to guard against (visible in the :exc:`BusyResourceError` - when triggered, e.g. "Another task is already {action} this resource") - - .. versionadded:: 4.1 - """ - - __slots__ = "__weakref__", "action", "_guarded" - - def __init__(self, action: str = "using"): - self.action: str = action - self._guarded = False - - def __enter__(self) -> None: - if self._guarded: - raise BusyResourceError(self.action) - - self._guarded = True - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self._guarded = False diff --git a/server/venv/Lib/site-packages/anyio/_core/_tasks.py b/server/venv/Lib/site-packages/anyio/_core/_tasks.py deleted file mode 100644 index 108393e..0000000 --- a/server/venv/Lib/site-packages/anyio/_core/_tasks.py +++ /dev/null @@ -1,415 +0,0 @@ -from __future__ import annotations - -import math -import sys -from collections.abc import ( - Coroutine, - Generator, -) -from contextlib import ( - contextmanager, -) -from contextvars import ContextVar -from enum import Enum, auto -from inspect import iscoroutine -from types import TracebackType -from typing import Any, Generic, final - -from ..abc import TaskGroup, TaskStatus -from ._eventloop import get_async_backend, get_cancelled_exc_class -from ._exceptions import TaskCancelled, TaskFailed, TaskNotFinished - -if sys.version_info >= (3, 13): - from typing import TypeVar -else: - from typing_extensions import TypeVar - -if sys.version_info >= (3, 11): - from typing import Never, TypeVarTuple -else: - from typing_extensions import Never, TypeVarTuple - -T = TypeVar("T") -T_co = TypeVar("T_co", covariant=True) -T_startval = TypeVar("T_startval", covariant=True, default=Never) -PosArgsT = TypeVarTuple("PosArgsT") - -_current_task_handle: ContextVar[TaskHandle] = ContextVar("_current_task_handle") - - -class _IgnoredTaskStatus(TaskStatus[object]): - def started(self, value: object = None) -> None: - pass - - -TASK_STATUS_IGNORED = _IgnoredTaskStatus() - - -class CancelScope: - """ - Wraps a unit of work that can be made separately cancellable. - - :param deadline: The time (clock value) when this scope is cancelled automatically - :param shield: ``True`` to shield the cancel scope from external cancellation - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - """ - - __slots__ = ("__weakref__",) - - def __new__( - cls, *, deadline: float = math.inf, shield: bool = False - ) -> CancelScope: - return get_async_backend().create_cancel_scope(shield=shield, deadline=deadline) - - def cancel(self, reason: str | None = None) -> None: - """ - Cancel this scope immediately. - - :param reason: a message describing the reason for the cancellation - - """ - raise NotImplementedError - - @property - def deadline(self) -> float: - """ - The time (clock value) when this scope is cancelled automatically. - - Will be ``float('inf')`` if no timeout has been set. - - """ - raise NotImplementedError - - @deadline.setter - def deadline(self, value: float) -> None: - raise NotImplementedError - - @property - def cancel_called(self) -> bool: - """``True`` if :meth:`cancel` has been called.""" - raise NotImplementedError - - @property - def cancelled_caught(self) -> bool: - """ - ``True`` if this scope suppressed a cancellation exception it itself raised. - - This is typically used to check if any work was interrupted, or to see if the - scope was cancelled due to its deadline being reached. The value will, however, - only be ``True`` if the cancellation was triggered by the scope itself (and not - an outer scope). - - """ - raise NotImplementedError - - @property - def shield(self) -> bool: - """ - ``True`` if this scope is shielded from external cancellation. - - While a scope is shielded, it will not receive cancellations from outside. - - """ - raise NotImplementedError - - @shield.setter - def shield(self, value: bool) -> None: - raise NotImplementedError - - def __enter__(self) -> CancelScope: - raise NotImplementedError - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - raise NotImplementedError - - -@contextmanager -def fail_after( - delay: float | None, shield: bool = False -) -> Generator[CancelScope, None, None]: - """ - Create a context manager which raises a :class:`TimeoutError` if does not finish in - time. - - :param delay: maximum allowed time (in seconds) before raising the exception, or - ``None`` to disable the timeout - :param shield: ``True`` to shield the cancel scope from external cancellation - :return: a context manager that yields a cancel scope - :rtype: :class:`~typing.ContextManager`\\[:class:`~anyio.CancelScope`\\] - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - current_time = get_async_backend().current_time - deadline = (current_time() + delay) if delay is not None else math.inf - with get_async_backend().create_cancel_scope( - deadline=deadline, shield=shield - ) as cancel_scope: - yield cancel_scope - - if cancel_scope.cancelled_caught and current_time() >= cancel_scope.deadline: - raise TimeoutError - - -def move_on_after(delay: float | None, shield: bool = False) -> CancelScope: - """ - Create a cancel scope with a deadline that expires after the given delay. - - :param delay: maximum allowed time (in seconds) before exiting the context block, or - ``None`` to disable the timeout - :param shield: ``True`` to shield the cancel scope from external cancellation - :return: a cancel scope - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - deadline = ( - (get_async_backend().current_time() + delay) if delay is not None else math.inf - ) - return get_async_backend().create_cancel_scope(deadline=deadline, shield=shield) - - -def current_effective_deadline() -> float: - """ - Return the nearest deadline among all the cancel scopes effective for the current - task. - - :return: a clock value from the event loop's internal clock (or ``float('inf')`` if - there is no deadline in effect, or ``float('-inf')`` if the current scope has - been cancelled) - :rtype: float - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().current_effective_deadline() - - -def create_task_group() -> TaskGroup: - """ - Create a task group. - - :return: a task group - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().create_task_group() - - -@final -class TaskHandle(Generic[T_co, T_startval]): - """ - Returned from the task-spawning methods of :class:`TaskGroup`. Can be awaited on to - get the return value of the task (or the raised exception). If the task was - terminated by a :exc:`BaseException`, :exc:`TaskFailed` will be raised (or its - subclass :exc:`TaskCancelled` if the task was cancelled). - - .. versionadded:: 4.14.0 - """ - - class Status(Enum): - """ - The status of a task handle. - - .. attribute:: PENDING - - The task has not finished yet. - .. attribute:: FINISHED - - The task has finished with a return value. - .. attribute:: CANCELLING - - The task has been cancelled but has not finished yet. - .. attribute:: CANCELLED - - The task was cancelled and has finished since. - .. attribute:: FAILED - - The task raised an exception. - """ - - PENDING = auto() - FINISHED = auto() - CANCELLING = auto() - CANCELLED = auto() - FAILED = auto() - - __slots__ = ( - "__weakref__", - "_coro", - "_name", - "_cancel_scope", - "_finished_event", - "_return_value", - "_start_value", - "_exception", - ) - - _return_value: T_co - _start_value: T_startval - - def __init__(self, coro: Coroutine[Any, Any, T_co], name: object) -> None: - from ._synchronization import Event - - self._coro = coro - self._cancel_scope = CancelScope() - self._finished_event = Event() - self._exception: BaseException | None = None - - if name is not None: - self._name = str(name) - elif iscoroutine(coro): - self._name = coro.__qualname__ - else: - self._name = str(coro) # coroutine-like object (e.g. asend() objects) - - async def _run_coro(self) -> None: - __tracebackhide__ = True - - with self._cancel_scope: - try: - retval = await self._coro - except BaseException as exc: - self._exception = exc - raise - else: - self._return_value = retval - finally: - self._finished_event.set() - del self # Break the reference cycle - - def cancel(self) -> None: - """ - Set the task to a cancelled state. - - This will interrupt any interruptible asynchronous operation, and will cause - any further awaits on this task to get immediately cancelled, unless done in - a shielded cancel scope. - - If the task has already finished, this method has no effect. - """ - if not self._finished_event.is_set(): - self._cancel_scope.cancel() - - @property - def coro(self) -> Coroutine[Any, Any, T_co]: - """ - The coroutine object that was passed to one of the task-spawning methods in - :class:`TaskGroup`. - """ - return self._coro - - @property - def status(self) -> TaskHandle.Status: - """ - The current status of the task. - - Every task starts in the :attr:`~TaskHandle.Status.PENDING` state. - If a task is cancelled while in this state, it will transition to the - :attr:`~TaskHandle.Status.CANCELLING` state. When the task finishes, it will - transition to one of the three final states ( - :attr:`~TaskHandle.Status.FINISHED`, :attr:`~TaskHandle.Status.FAILED`, or - :attr:`~TaskHandle.Status.CANCELLING`) depending on the exception the task - raised, if any. No other status transitions will happen. - """ - if not self._finished_event.is_set(): - if self._cancel_scope.cancel_called: - return TaskHandle.Status.CANCELLING - else: - return TaskHandle.Status.PENDING - elif self._exception is not None: - if isinstance(self._exception, get_cancelled_exc_class()): - return TaskHandle.Status.CANCELLED - else: - return TaskHandle.Status.FAILED - else: - return TaskHandle.Status.FINISHED - - @property - def name(self) -> str: - """The name of the task.""" - return self._name - - @property - def exception(self) -> BaseException | None: - """ - The exception raised by the task, or ``None`` if it finished without raising. - - :raises TaskNotFinished: if the task has not finished yet - :raises TaskCancelled: if the task was cancelled - - """ - match self.status: - case TaskHandle.Status.PENDING: - raise TaskNotFinished("the task has not finished yet") - case TaskHandle.Status.FINISHED: - return None - case TaskHandle.Status.CANCELLING: - raise TaskCancelled("the task was cancelled") - case TaskHandle.Status.CANCELLED: - raise TaskCancelled("the task was cancelled") from self._exception - case TaskHandle.Status.FAILED: - return self._exception - - @property - def return_value(self) -> T_co: - """ - The return value of the task. - - :raises TaskNotFinished: if the task has not finished yet - :raises TaskCancelled: if the task was cancelled - :raises TaskFailed: if the task raised an exception - - """ - match self.status: - case TaskHandle.Status.PENDING: - raise TaskNotFinished("the task has not finished yet") - case TaskHandle.Status.FINISHED: - return self._return_value - case TaskHandle.Status.CANCELLING: - raise TaskCancelled("the task was cancelled") - case TaskHandle.Status.CANCELLED: - raise TaskCancelled("the task was cancelled") from self._exception - case TaskHandle.Status.FAILED: - raise TaskFailed("the task raised an exception") from self._exception - - @property - def start_value(self) -> T_startval: - """ - The value passed to :meth:`task_status.started() <.abc.TaskStatus.started>`, - - :raises RuntimeError: if the task was not started with :meth:`TaskGroup.start() - <.abc.TaskGroup.start>` - """ - try: - return self._start_value - except AttributeError: - raise RuntimeError( - "the task was not started with TaskGroup.start()" - ) from None - - async def wait(self) -> None: - """ - Wait for the task to finish. - - This method will return as soon as the task has finished, no matter how it - happened. - """ - await self._finished_event.wait() - - def __await__(self) -> Generator[Any, Any, T_co]: - yield from self._finished_event.wait().__await__() - return self.return_value - - def __repr__(self) -> str: - return ( - f"<{self.__class__.__name__} {self.status.name.lower()} " - f"name={self._name!r} coro={self._coro!r}>" - ) diff --git a/server/venv/Lib/site-packages/anyio/_core/_tempfile.py b/server/venv/Lib/site-packages/anyio/_core/_tempfile.py deleted file mode 100644 index 75a09f7..0000000 --- a/server/venv/Lib/site-packages/anyio/_core/_tempfile.py +++ /dev/null @@ -1,613 +0,0 @@ -from __future__ import annotations - -import os -import sys -import tempfile -from collections.abc import Iterable -from io import BytesIO, TextIOWrapper -from types import TracebackType -from typing import ( - TYPE_CHECKING, - Any, - AnyStr, - Generic, - overload, -) - -from .. import to_thread -from .._core._fileio import AsyncFile -from ..lowlevel import checkpoint_if_cancelled - -if TYPE_CHECKING: - from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer - - -class TemporaryFile(Generic[AnyStr]): - """ - An asynchronous temporary file that is automatically created and cleaned up. - - This class provides an asynchronous context manager interface to a temporary file. - The file is created using Python's standard `tempfile.TemporaryFile` function in a - background thread, and is wrapped as an asynchronous file using `AsyncFile`. - - :param mode: The mode in which the file is opened. Defaults to "w+b". - :param buffering: The buffering policy (-1 means the default buffering). - :param encoding: The encoding used to decode or encode the file. Only applicable in - text mode. - :param newline: Controls how universal newlines mode works (only applicable in text - mode). - :param suffix: The suffix for the temporary file name. - :param prefix: The prefix for the temporary file name. - :param dir: The directory in which the temporary file is created. - :param errors: The error handling scheme used for encoding/decoding errors. - """ - - _async_file: AsyncFile[AnyStr] - - @overload - def __init__( - self: TemporaryFile[bytes], - mode: OpenBinaryMode = ..., - buffering: int = ..., - encoding: str | None = ..., - newline: str | None = ..., - suffix: str | None = ..., - prefix: str | None = ..., - dir: str | None = ..., - *, - errors: str | None = ..., - ): ... - @overload - def __init__( - self: TemporaryFile[str], - mode: OpenTextMode, - buffering: int = ..., - encoding: str | None = ..., - newline: str | None = ..., - suffix: str | None = ..., - prefix: str | None = ..., - dir: str | None = ..., - *, - errors: str | None = ..., - ): ... - - def __init__( - self, - mode: OpenTextMode | OpenBinaryMode = "w+b", - buffering: int = -1, - encoding: str | None = None, - newline: str | None = None, - suffix: str | None = None, - prefix: str | None = None, - dir: str | None = None, - *, - errors: str | None = None, - ) -> None: - self.mode = mode - self.buffering = buffering - self.encoding = encoding - self.newline = newline - self.suffix: str | None = suffix - self.prefix: str | None = prefix - self.dir: str | None = dir - self.errors = errors - - async def __aenter__(self) -> AsyncFile[AnyStr]: - fp = await to_thread.run_sync( - lambda: tempfile.TemporaryFile( - self.mode, - self.buffering, - self.encoding, - self.newline, - self.suffix, - self.prefix, - self.dir, - errors=self.errors, - ) - ) - self._async_file = AsyncFile(fp) - return self._async_file - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - traceback: TracebackType | None, - ) -> None: - await self._async_file.aclose() - - -class NamedTemporaryFile(Generic[AnyStr]): - """ - An asynchronous named temporary file that is automatically created and cleaned up. - - This class provides an asynchronous context manager for a temporary file with a - visible name in the file system. It uses Python's standard - :func:`~tempfile.NamedTemporaryFile` function and wraps the file object with - :class:`AsyncFile` for asynchronous operations. - - :param mode: The mode in which the file is opened. Defaults to "w+b". - :param buffering: The buffering policy (-1 means the default buffering). - :param encoding: The encoding used to decode or encode the file. Only applicable in - text mode. - :param newline: Controls how universal newlines mode works (only applicable in text - mode). - :param suffix: The suffix for the temporary file name. - :param prefix: The prefix for the temporary file name. - :param dir: The directory in which the temporary file is created. - :param delete: Whether to delete the file when it is closed. - :param errors: The error handling scheme used for encoding/decoding errors. - :param delete_on_close: (Python 3.12+) Whether to delete the file on close. - """ - - _async_file: AsyncFile[AnyStr] - - @overload - def __init__( - self: NamedTemporaryFile[bytes], - mode: OpenBinaryMode = ..., - buffering: int = ..., - encoding: str | None = ..., - newline: str | None = ..., - suffix: str | None = ..., - prefix: str | None = ..., - dir: str | None = ..., - delete: bool = ..., - *, - errors: str | None = ..., - delete_on_close: bool = ..., - ): ... - @overload - def __init__( - self: NamedTemporaryFile[str], - mode: OpenTextMode, - buffering: int = ..., - encoding: str | None = ..., - newline: str | None = ..., - suffix: str | None = ..., - prefix: str | None = ..., - dir: str | None = ..., - delete: bool = ..., - *, - errors: str | None = ..., - delete_on_close: bool = ..., - ): ... - - def __init__( - self, - mode: OpenBinaryMode | OpenTextMode = "w+b", - buffering: int = -1, - encoding: str | None = None, - newline: str | None = None, - suffix: str | None = None, - prefix: str | None = None, - dir: str | None = None, - delete: bool = True, - *, - errors: str | None = None, - delete_on_close: bool = True, - ) -> None: - self._params: dict[str, Any] = { - "mode": mode, - "buffering": buffering, - "encoding": encoding, - "newline": newline, - "suffix": suffix, - "prefix": prefix, - "dir": dir, - "delete": delete, - "errors": errors, - } - if sys.version_info >= (3, 12): - self._params["delete_on_close"] = delete_on_close - - async def __aenter__(self) -> AsyncFile[AnyStr]: - fp = await to_thread.run_sync( - lambda: tempfile.NamedTemporaryFile(**self._params) - ) - self._async_file = AsyncFile(fp) - return self._async_file - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - traceback: TracebackType | None, - ) -> None: - await self._async_file.aclose() - - -class SpooledTemporaryFile(AsyncFile[AnyStr]): - """ - An asynchronous spooled temporary file that starts in memory and is spooled to disk. - - This class provides an asynchronous interface to a spooled temporary file, much like - Python's standard :class:`~tempfile.SpooledTemporaryFile`. It supports asynchronous - write operations and provides a method to force a rollover to disk. - - :param max_size: Maximum size in bytes before the file is rolled over to disk. - :param mode: The mode in which the file is opened. Defaults to "w+b". - :param buffering: The buffering policy (-1 means the default buffering). - :param encoding: The encoding used to decode or encode the file (text mode only). - :param newline: Controls how universal newlines mode works (text mode only). - :param suffix: The suffix for the temporary file name. - :param prefix: The prefix for the temporary file name. - :param dir: The directory in which the temporary file is created. - :param errors: The error handling scheme used for encoding/decoding errors. - """ - - _rolled: bool = False - - @overload - def __init__( - self: SpooledTemporaryFile[bytes], - max_size: int = ..., - mode: OpenBinaryMode = ..., - buffering: int = ..., - encoding: str | None = ..., - newline: str | None = ..., - suffix: str | None = ..., - prefix: str | None = ..., - dir: str | None = ..., - *, - errors: str | None = ..., - ): ... - @overload - def __init__( - self: SpooledTemporaryFile[str], - max_size: int = ..., - mode: OpenTextMode = ..., - buffering: int = ..., - encoding: str | None = ..., - newline: str | None = ..., - suffix: str | None = ..., - prefix: str | None = ..., - dir: str | None = ..., - *, - errors: str | None = ..., - ): ... - - def __init__( - self, - max_size: int = 0, - mode: OpenBinaryMode | OpenTextMode = "w+b", - buffering: int = -1, - encoding: str | None = None, - newline: str | None = None, - suffix: str | None = None, - prefix: str | None = None, - dir: str | None = None, - *, - errors: str | None = None, - ) -> None: - self._tempfile_params: dict[str, Any] = { - "mode": mode, - "buffering": buffering, - "encoding": encoding, - "newline": newline, - "suffix": suffix, - "prefix": prefix, - "dir": dir, - "errors": errors, - } - self._max_size = max_size - if "b" in mode: - super().__init__(BytesIO()) # type: ignore[arg-type] - else: - super().__init__( - TextIOWrapper( # type: ignore[arg-type] - BytesIO(), - encoding=encoding, - errors=errors, - newline=newline, - write_through=True, - ) - ) - - async def aclose(self) -> None: - if not self._rolled: - self._fp.close() - return - - await super().aclose() - - async def _check(self) -> None: - if self._rolled or self._fp.tell() <= self._max_size: - return - - await self.rollover() - - async def rollover(self) -> None: - if self._rolled: - return - - self._rolled = True - buffer = self._fp - buffer.seek(0) - self._fp = await to_thread.run_sync( - lambda: tempfile.TemporaryFile(**self._tempfile_params) - ) - await self.write(buffer.read()) - buffer.close() - - @property - def closed(self) -> bool: - return self._fp.closed - - async def read(self, size: int = -1) -> AnyStr: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.read(size) - - return await super().read(size) # type: ignore[return-value] - - async def read1(self: SpooledTemporaryFile[bytes], size: int = -1) -> bytes: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.read1(size) - - return await super().read1(size) - - async def readline(self) -> AnyStr: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.readline() - - return await super().readline() # type: ignore[return-value] - - async def readlines(self) -> list[AnyStr]: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.readlines() - - return await super().readlines() # type: ignore[return-value] - - async def readinto(self: SpooledTemporaryFile[bytes], b: WriteableBuffer) -> int: - if not self._rolled: - await checkpoint_if_cancelled() - self._fp.readinto(b) - - return await super().readinto(b) - - async def readinto1(self: SpooledTemporaryFile[bytes], b: WriteableBuffer) -> int: - if not self._rolled: - await checkpoint_if_cancelled() - self._fp.readinto(b) - - return await super().readinto1(b) - - async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.seek(offset, whence) - - return await super().seek(offset, whence) - - async def tell(self) -> int: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.tell() - - return await super().tell() - - async def truncate(self, size: int | None = None) -> int: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.truncate(size) - - return await super().truncate(size) - - @overload - async def write(self: SpooledTemporaryFile[bytes], b: ReadableBuffer) -> int: ... - @overload - async def write(self: SpooledTemporaryFile[str], b: str) -> int: ... - - async def write(self, b: ReadableBuffer | str) -> int: - """ - Asynchronously write data to the spooled temporary file. - - If the file has not yet been rolled over, the data is written synchronously, - and a rollover is triggered if the size exceeds the maximum size. - - :param s: The data to write. - :return: The number of bytes written. - :raises RuntimeError: If the underlying file is not initialized. - - """ - if not self._rolled: - await checkpoint_if_cancelled() - result = self._fp.write(b) - await self._check() - return result - - return await super().write(b) # type: ignore[misc] - - @overload - async def writelines( - self: SpooledTemporaryFile[bytes], lines: Iterable[ReadableBuffer] - ) -> None: ... - @overload - async def writelines( - self: SpooledTemporaryFile[str], lines: Iterable[str] - ) -> None: ... - - async def writelines(self, lines: Iterable[str] | Iterable[ReadableBuffer]) -> None: - """ - Asynchronously write a list of lines to the spooled temporary file. - - If the file has not yet been rolled over, the lines are written synchronously, - and a rollover is triggered if the size exceeds the maximum size. - - :param lines: An iterable of lines to write. - :raises RuntimeError: If the underlying file is not initialized. - - """ - if not self._rolled: - await checkpoint_if_cancelled() - result = self._fp.writelines(lines) - await self._check() - return result - - return await super().writelines(lines) # type: ignore[misc] - - -class TemporaryDirectory(Generic[AnyStr]): - """ - An asynchronous temporary directory that is created and cleaned up automatically. - - This class provides an asynchronous context manager for creating a temporary - directory. It wraps Python's standard :class:`~tempfile.TemporaryDirectory` to - perform directory creation and cleanup operations in a background thread. - - :param suffix: Suffix to be added to the temporary directory name. - :param prefix: Prefix to be added to the temporary directory name. - :param dir: The parent directory where the temporary directory is created. - :param ignore_cleanup_errors: Whether to ignore errors during cleanup - :param delete: Whether to delete the directory upon closing (Python 3.12+). - """ - - def __init__( - self, - suffix: AnyStr | None = None, - prefix: AnyStr | None = None, - dir: AnyStr | None = None, - *, - ignore_cleanup_errors: bool = False, - delete: bool = True, - ) -> None: - self.suffix: AnyStr | None = suffix - self.prefix: AnyStr | None = prefix - self.dir: AnyStr | None = dir - self.ignore_cleanup_errors = ignore_cleanup_errors - self.delete = delete - - self._tempdir: tempfile.TemporaryDirectory | None = None - - async def __aenter__(self) -> str: - params: dict[str, Any] = { - "suffix": self.suffix, - "prefix": self.prefix, - "dir": self.dir, - "ignore_cleanup_errors": self.ignore_cleanup_errors, - } - if sys.version_info >= (3, 12): - params["delete"] = self.delete - - self._tempdir = await to_thread.run_sync( - lambda: tempfile.TemporaryDirectory(**params) - ) - return await to_thread.run_sync(self._tempdir.__enter__) - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - traceback: TracebackType | None, - ) -> None: - if self._tempdir is not None: - await to_thread.run_sync( - self._tempdir.__exit__, exc_type, exc_value, traceback - ) - - async def cleanup(self) -> None: - if self._tempdir is not None: - await to_thread.run_sync(self._tempdir.cleanup) - - -@overload -async def mkstemp( - suffix: str | None = None, - prefix: str | None = None, - dir: str | None = None, - text: bool = False, -) -> tuple[int, str]: ... - - -@overload -async def mkstemp( - suffix: bytes | None = None, - prefix: bytes | None = None, - dir: bytes | None = None, - text: bool = False, -) -> tuple[int, bytes]: ... - - -async def mkstemp( - suffix: AnyStr | None = None, - prefix: AnyStr | None = None, - dir: AnyStr | None = None, - text: bool = False, -) -> tuple[int, str | bytes]: - """ - Asynchronously create a temporary file and return an OS-level handle and the file - name. - - This function wraps `tempfile.mkstemp` and executes it in a background thread. - - :param suffix: Suffix to be added to the file name. - :param prefix: Prefix to be added to the file name. - :param dir: Directory in which the temporary file is created. - :param text: Whether the file is opened in text mode. - :return: A tuple containing the file descriptor and the file name. - - """ - return await to_thread.run_sync(tempfile.mkstemp, suffix, prefix, dir, text) - - -@overload -async def mkdtemp( - suffix: str | None = None, - prefix: str | None = None, - dir: str | None = None, -) -> str: ... - - -@overload -async def mkdtemp( - suffix: bytes | None = None, - prefix: bytes | None = None, - dir: bytes | None = None, -) -> bytes: ... - - -async def mkdtemp( - suffix: AnyStr | None = None, - prefix: AnyStr | None = None, - dir: AnyStr | None = None, -) -> str | bytes: - """ - Asynchronously create a temporary directory and return its path. - - This function wraps `tempfile.mkdtemp` and executes it in a background thread. - - :param suffix: Suffix to be added to the directory name. - :param prefix: Prefix to be added to the directory name. - :param dir: Parent directory where the temporary directory is created. - :return: The path of the created temporary directory. - - """ - return await to_thread.run_sync(tempfile.mkdtemp, suffix, prefix, dir) - - -async def gettempdir() -> str: - """ - Asynchronously return the name of the directory used for temporary files. - - This function wraps `tempfile.gettempdir` and executes it in a background thread. - - :return: The path of the temporary directory as a string. - - """ - return await to_thread.run_sync(tempfile.gettempdir) - - -async def gettempdirb() -> bytes: - """ - Asynchronously return the name of the directory used for temporary files in bytes. - - This function wraps `tempfile.gettempdirb` and executes it in a background thread. - - :return: The path of the temporary directory as bytes. - - """ - return await to_thread.run_sync(tempfile.gettempdirb) diff --git a/server/venv/Lib/site-packages/anyio/_core/_testing.py b/server/venv/Lib/site-packages/anyio/_core/_testing.py deleted file mode 100644 index 369e65c..0000000 --- a/server/venv/Lib/site-packages/anyio/_core/_testing.py +++ /dev/null @@ -1,82 +0,0 @@ -from __future__ import annotations - -from collections.abc import Awaitable, Generator -from typing import Any, cast - -from ._eventloop import get_async_backend - - -class TaskInfo: - """ - Represents an asynchronous task. - - :ivar int id: the unique identifier of the task - :ivar parent_id: the identifier of the parent task, if any - :vartype parent_id: Optional[int] - :ivar str name: the description of the task (if any) - :ivar ~collections.abc.Coroutine coro: the coroutine object of the task - """ - - __slots__ = "_name", "id", "parent_id", "name", "coro" - - def __init__( - self, - id: int, - parent_id: int | None, - name: str | None, - coro: Generator[Any, Any, Any] | Awaitable[Any], - ): - func = get_current_task - self._name = f"{func.__module__}.{func.__qualname__}" - self.id: int = id - self.parent_id: int | None = parent_id - self.name: str | None = name - self.coro: Generator[Any, Any, Any] | Awaitable[Any] = coro - - def __eq__(self, other: object) -> bool: - if isinstance(other, TaskInfo): - return self.id == other.id - - return NotImplemented - - def __hash__(self) -> int: - return hash(self.id) - - def __repr__(self) -> str: - return f"{self.__class__.__name__}(id={self.id!r}, name={self.name!r})" - - def has_pending_cancellation(self) -> bool: - """ - Return ``True`` if the task has a cancellation pending, ``False`` otherwise. - - """ - return False - - -def get_current_task() -> TaskInfo: - """ - Return the current task. - - :return: a representation of the current task - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().get_current_task() - - -def get_running_tasks() -> list[TaskInfo]: - """ - Return a list of running tasks in the current event loop. - - :return: a list of task info objects - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return cast("list[TaskInfo]", get_async_backend().get_running_tasks()) - - -async def wait_all_tasks_blocked() -> None: - """Wait until all other tasks are waiting for something.""" - await get_async_backend().wait_all_tasks_blocked() diff --git a/server/venv/Lib/site-packages/anyio/_core/_typedattr.py b/server/venv/Lib/site-packages/anyio/_core/_typedattr.py deleted file mode 100644 index f358a44..0000000 --- a/server/venv/Lib/site-packages/anyio/_core/_typedattr.py +++ /dev/null @@ -1,81 +0,0 @@ -from __future__ import annotations - -from collections.abc import Callable, Mapping -from typing import Any, TypeVar, final, overload - -from ._exceptions import TypedAttributeLookupError - -T_Attr = TypeVar("T_Attr") -T_Default = TypeVar("T_Default") -undefined = object() - - -def typed_attribute() -> Any: - """Return a unique object, used to mark typed attributes.""" - return object() - - -class TypedAttributeSet: - """ - Superclass for typed attribute collections. - - Checks that every public attribute of every subclass has a type annotation. - """ - - def __init_subclass__(cls) -> None: - annotations: dict[str, Any] = getattr(cls, "__annotations__", {}) - for attrname in dir(cls): - if not attrname.startswith("_") and attrname not in annotations: - raise TypeError( - f"Attribute {attrname!r} is missing its type annotation" - ) - - super().__init_subclass__() - - -class TypedAttributeProvider: - """Base class for classes that wish to provide typed extra attributes.""" - - @property - def extra_attributes(self) -> Mapping[T_Attr, Callable[[], T_Attr]]: - """ - A mapping of the extra attributes to callables that return the corresponding - values. - - If the provider wraps another provider, the attributes from that wrapper should - also be included in the returned mapping (but the wrapper may override the - callables from the wrapped instance). - - """ - return {} - - @overload - def extra(self, attribute: T_Attr) -> T_Attr: ... - - @overload - def extra(self, attribute: T_Attr, default: T_Default) -> T_Attr | T_Default: ... - - @final - def extra(self, attribute: Any, default: object = undefined) -> object: - """ - extra(attribute, default=undefined) - - Return the value of the given typed extra attribute. - - :param attribute: the attribute (member of a :class:`~TypedAttributeSet`) to - look for - :param default: the value that should be returned if no value is found for the - attribute - :raises ~anyio.TypedAttributeLookupError: if the search failed and no default - value was given - - """ - try: - getter = self.extra_attributes[attribute] - except KeyError: - if default is undefined: - raise TypedAttributeLookupError("Attribute not found") from None - else: - return default - - return getter() diff --git a/server/venv/Lib/site-packages/anyio/abc/__init__.py b/server/venv/Lib/site-packages/anyio/abc/__init__.py deleted file mode 100644 index d560ce3..0000000 --- a/server/venv/Lib/site-packages/anyio/abc/__init__.py +++ /dev/null @@ -1,58 +0,0 @@ -from __future__ import annotations - -from ._eventloop import AsyncBackend as AsyncBackend -from ._resources import AsyncResource as AsyncResource -from ._sockets import ConnectedUDPSocket as ConnectedUDPSocket -from ._sockets import ConnectedUNIXDatagramSocket as ConnectedUNIXDatagramSocket -from ._sockets import IPAddressType as IPAddressType -from ._sockets import IPSockAddrType as IPSockAddrType -from ._sockets import SocketAttribute as SocketAttribute -from ._sockets import SocketListener as SocketListener -from ._sockets import SocketStream as SocketStream -from ._sockets import UDPPacketType as UDPPacketType -from ._sockets import UDPSocket as UDPSocket -from ._sockets import UNIXDatagramPacketType as UNIXDatagramPacketType -from ._sockets import UNIXDatagramSocket as UNIXDatagramSocket -from ._sockets import UNIXSocketStream as UNIXSocketStream -from ._streams import AnyByteReceiveStream as AnyByteReceiveStream -from ._streams import AnyByteSendStream as AnyByteSendStream -from ._streams import AnyByteStream as AnyByteStream -from ._streams import AnyByteStreamConnectable as AnyByteStreamConnectable -from ._streams import AnyUnreliableByteReceiveStream as AnyUnreliableByteReceiveStream -from ._streams import AnyUnreliableByteSendStream as AnyUnreliableByteSendStream -from ._streams import AnyUnreliableByteStream as AnyUnreliableByteStream -from ._streams import ByteReceiveStream as ByteReceiveStream -from ._streams import ByteSendStream as ByteSendStream -from ._streams import ByteStream as ByteStream -from ._streams import ByteStreamConnectable as ByteStreamConnectable -from ._streams import Listener as Listener -from ._streams import ObjectReceiveStream as ObjectReceiveStream -from ._streams import ObjectSendStream as ObjectSendStream -from ._streams import ObjectStream as ObjectStream -from ._streams import ObjectStreamConnectable as ObjectStreamConnectable -from ._streams import UnreliableObjectReceiveStream as UnreliableObjectReceiveStream -from ._streams import UnreliableObjectSendStream as UnreliableObjectSendStream -from ._streams import UnreliableObjectStream as UnreliableObjectStream -from ._subprocesses import Process as Process -from ._tasks import TaskGroup as TaskGroup -from ._tasks import TaskStatus as TaskStatus -from ._testing import TestRunner as TestRunner - -# Re-exported here, for backwards compatibility -# isort: off -from .._core._synchronization import ( - CapacityLimiter as CapacityLimiter, - Condition as Condition, - Event as Event, - Lock as Lock, - Semaphore as Semaphore, -) -from .._core._tasks import CancelScope as CancelScope -from ..from_thread import BlockingPortal as BlockingPortal - -# Re-export imports so they look like they live directly in this package -for __value in list(locals().values()): - if getattr(__value, "__module__", "").startswith("anyio.abc."): - __value.__module__ = __name__ - -del __value diff --git a/server/venv/Lib/site-packages/anyio/abc/_eventloop.py b/server/venv/Lib/site-packages/anyio/abc/_eventloop.py deleted file mode 100644 index cad3fa7..0000000 --- a/server/venv/Lib/site-packages/anyio/abc/_eventloop.py +++ /dev/null @@ -1,410 +0,0 @@ -from __future__ import annotations - -import math -import sys -from abc import ABCMeta, abstractmethod -from collections.abc import AsyncIterator, Awaitable, Callable, Coroutine, Sequence -from contextlib import AbstractContextManager -from os import PathLike -from signal import Signals -from socket import AddressFamily, SocketKind, socket -from typing import ( - IO, - TYPE_CHECKING, - Any, - TypeAlias, - TypeVar, - overload, -) - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -if TYPE_CHECKING: - from _typeshed import FileDescriptorLike - - from .._core._synchronization import CapacityLimiter, Event, Lock, Semaphore - from .._core._tasks import CancelScope - from .._core._testing import TaskInfo - from ._sockets import ( - ConnectedUDPSocket, - ConnectedUNIXDatagramSocket, - IPSockAddrType, - SocketListener, - SocketStream, - UDPSocket, - UNIXDatagramSocket, - UNIXSocketStream, - ) - from ._subprocesses import Process - from ._tasks import TaskGroup - from ._testing import TestRunner - -T_Retval = TypeVar("T_Retval") -T_co = TypeVar("T_co", covariant=True) -PosArgsT = TypeVarTuple("PosArgsT") -StrOrBytesPath: TypeAlias = str | bytes | PathLike[str] | PathLike[bytes] - - -class AsyncBackend(metaclass=ABCMeta): - @classmethod - @abstractmethod - def run( - cls, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - args: tuple[Unpack[PosArgsT]], - kwargs: dict[str, Any], - options: dict[str, Any], - ) -> T_Retval: - """ - Run the given coroutine function in an asynchronous event loop. - - The current thread must not be already running an event loop. - - :param func: a coroutine function - :param args: positional arguments to ``func`` - :param kwargs: positional arguments to ``func`` - :param options: keyword arguments to call the backend ``run()`` implementation - with - :return: the return value of the coroutine function - """ - - @classmethod - @abstractmethod - def current_token(cls) -> object: - """ - Return an object that allows other threads to run code inside the event loop. - - :return: a token object, specific to the event loop running in the current - thread - """ - - @classmethod - @abstractmethod - def current_time(cls) -> float: - """ - Return the current value of the event loop's internal clock. - - :return: the clock value (seconds) - """ - - @classmethod - @abstractmethod - def cancelled_exception_class(cls) -> type[BaseException]: - """Return the exception class that is raised in a task if it's cancelled.""" - - @classmethod - @abstractmethod - async def checkpoint(cls) -> None: - """ - Check if the task has been cancelled, and allow rescheduling of other tasks. - - This is effectively the same as running :meth:`checkpoint_if_cancelled` and then - :meth:`cancel_shielded_checkpoint`. - """ - - @classmethod - async def checkpoint_if_cancelled(cls) -> None: - """ - Check if the current task group has been cancelled. - - This will check if the task has been cancelled, but will not allow other tasks - to be scheduled if not. - - """ - if cls.current_effective_deadline() == -math.inf: - await cls.checkpoint() - - @classmethod - async def cancel_shielded_checkpoint(cls) -> None: - """ - Allow the rescheduling of other tasks. - - This will give other tasks the opportunity to run, but without checking if the - current task group has been cancelled, unlike with :meth:`checkpoint`. - - """ - with cls.create_cancel_scope(shield=True): - await cls.sleep(0) - - @classmethod - @abstractmethod - async def sleep(cls, delay: float) -> None: - """ - Pause the current task for the specified duration. - - :param delay: the duration, in seconds - """ - - @classmethod - @abstractmethod - def create_cancel_scope( - cls, *, deadline: float = math.inf, shield: bool = False - ) -> CancelScope: - pass - - @classmethod - @abstractmethod - def current_effective_deadline(cls) -> float: - """ - Return the nearest deadline among all the cancel scopes effective for the - current task. - - :return: - - a clock value from the event loop's internal clock - - ``inf`` if there is no deadline in effect - - ``-inf`` if the current scope has been cancelled - :rtype: float - """ - - @classmethod - @abstractmethod - def create_task_group(cls) -> TaskGroup: - pass - - @classmethod - @abstractmethod - def create_event(cls) -> Event: - pass - - @classmethod - @abstractmethod - def create_lock(cls, *, fast_acquire: bool) -> Lock: - pass - - @classmethod - @abstractmethod - def create_semaphore( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> Semaphore: - pass - - @classmethod - @abstractmethod - def create_capacity_limiter(cls, total_tokens: float) -> CapacityLimiter: - pass - - @classmethod - @abstractmethod - async def run_sync_in_worker_thread( - cls, - func: Callable[[Unpack[PosArgsT]], T_Retval], - args: tuple[Unpack[PosArgsT]], - abandon_on_cancel: bool = False, - limiter: CapacityLimiter | None = None, - ) -> T_Retval: - pass - - @classmethod - @abstractmethod - def check_cancelled(cls) -> None: - pass - - @classmethod - @abstractmethod - def run_async_from_thread( - cls, - func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]], - args: tuple[Unpack[PosArgsT]], - token: object, - ) -> T_co: - pass - - @classmethod - @abstractmethod - def run_sync_from_thread( - cls, - func: Callable[[Unpack[PosArgsT]], T_Retval], - args: tuple[Unpack[PosArgsT]], - token: object, - ) -> T_Retval: - pass - - @classmethod - @abstractmethod - async def open_process( - cls, - command: StrOrBytesPath | Sequence[StrOrBytesPath], - *, - stdin: int | IO[Any] | None, - stdout: int | IO[Any] | None, - stderr: int | IO[Any] | None, - **kwargs: Any, - ) -> Process: - pass - - @classmethod - @abstractmethod - def setup_process_pool_exit_at_shutdown(cls, workers: set[Process]) -> None: - pass - - @classmethod - @abstractmethod - async def connect_tcp( - cls, host: str, port: int, local_address: IPSockAddrType | None = None - ) -> SocketStream: - pass - - @classmethod - @abstractmethod - async def connect_unix(cls, path: str | bytes) -> UNIXSocketStream: - pass - - @classmethod - @abstractmethod - def create_tcp_listener(cls, sock: socket) -> SocketListener: - pass - - @classmethod - @abstractmethod - def create_unix_listener(cls, sock: socket) -> SocketListener: - pass - - @classmethod - @abstractmethod - async def create_udp_socket( - cls, - family: AddressFamily, - local_address: IPSockAddrType | None, - remote_address: IPSockAddrType | None, - reuse_port: bool, - ) -> UDPSocket | ConnectedUDPSocket: - pass - - @classmethod - @overload - async def create_unix_datagram_socket( - cls, raw_socket: socket, remote_path: None - ) -> UNIXDatagramSocket: ... - - @classmethod - @overload - async def create_unix_datagram_socket( - cls, raw_socket: socket, remote_path: str | bytes - ) -> ConnectedUNIXDatagramSocket: ... - - @classmethod - @abstractmethod - async def create_unix_datagram_socket( - cls, raw_socket: socket, remote_path: str | bytes | None - ) -> UNIXDatagramSocket | ConnectedUNIXDatagramSocket: - pass - - @classmethod - @abstractmethod - async def getaddrinfo( - cls, - host: bytes | str | None, - port: str | int | None, - *, - family: int | AddressFamily = 0, - type: int | SocketKind = 0, - proto: int = 0, - flags: int = 0, - ) -> Sequence[ - tuple[ - AddressFamily, - SocketKind, - int, - str, - tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], - ] - ]: - pass - - @classmethod - @abstractmethod - async def getnameinfo( - cls, sockaddr: IPSockAddrType, flags: int = 0 - ) -> tuple[str, str]: - pass - - @classmethod - @abstractmethod - async def wait_readable(cls, obj: FileDescriptorLike) -> None: - pass - - @classmethod - @abstractmethod - async def wait_writable(cls, obj: FileDescriptorLike) -> None: - pass - - @classmethod - @abstractmethod - def notify_closing(cls, obj: FileDescriptorLike) -> None: - pass - - @classmethod - @abstractmethod - async def wrap_listener_socket(cls, sock: socket) -> SocketListener: - pass - - @classmethod - @abstractmethod - async def wrap_stream_socket(cls, sock: socket) -> SocketStream: - pass - - @classmethod - @abstractmethod - async def wrap_unix_stream_socket(cls, sock: socket) -> UNIXSocketStream: - pass - - @classmethod - @abstractmethod - async def wrap_udp_socket(cls, sock: socket) -> UDPSocket: - pass - - @classmethod - @abstractmethod - async def wrap_connected_udp_socket(cls, sock: socket) -> ConnectedUDPSocket: - pass - - @classmethod - @abstractmethod - async def wrap_unix_datagram_socket(cls, sock: socket) -> UNIXDatagramSocket: - pass - - @classmethod - @abstractmethod - async def wrap_connected_unix_datagram_socket( - cls, sock: socket - ) -> ConnectedUNIXDatagramSocket: - pass - - @classmethod - @abstractmethod - def current_default_thread_limiter(cls) -> CapacityLimiter: - pass - - @classmethod - @abstractmethod - def open_signal_receiver( - cls, *signals: Signals - ) -> AbstractContextManager[AsyncIterator[Signals]]: - pass - - @classmethod - @abstractmethod - def get_current_task(cls) -> TaskInfo: - pass - - @classmethod - @abstractmethod - def get_running_tasks(cls) -> Sequence[TaskInfo]: - pass - - @classmethod - @abstractmethod - async def wait_all_tasks_blocked(cls) -> None: - pass - - @classmethod - @abstractmethod - def create_test_runner(cls, options: dict[str, Any]) -> TestRunner: - pass diff --git a/server/venv/Lib/site-packages/anyio/abc/_resources.py b/server/venv/Lib/site-packages/anyio/abc/_resources.py deleted file mode 100644 index 10df115..0000000 --- a/server/venv/Lib/site-packages/anyio/abc/_resources.py +++ /dev/null @@ -1,33 +0,0 @@ -from __future__ import annotations - -from abc import ABCMeta, abstractmethod -from types import TracebackType -from typing import TypeVar - -T = TypeVar("T") - - -class AsyncResource(metaclass=ABCMeta): - """ - Abstract base class for all closeable asynchronous resources. - - Works as an asynchronous context manager which returns the instance itself on enter, - and calls :meth:`aclose` on exit. - """ - - __slots__ = () - - async def __aenter__(self: T) -> T: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - await self.aclose() - - @abstractmethod - async def aclose(self) -> None: - """Close the resource.""" diff --git a/server/venv/Lib/site-packages/anyio/abc/_sockets.py b/server/venv/Lib/site-packages/anyio/abc/_sockets.py deleted file mode 100644 index feb26bd..0000000 --- a/server/venv/Lib/site-packages/anyio/abc/_sockets.py +++ /dev/null @@ -1,399 +0,0 @@ -from __future__ import annotations - -import errno -import socket -from abc import abstractmethod -from collections.abc import Callable, Collection, Mapping -from contextlib import AsyncExitStack -from io import IOBase -from ipaddress import IPv4Address, IPv6Address -from socket import AddressFamily -from typing import Any, TypeAlias, TypeVar - -from .._core._eventloop import get_async_backend -from .._core._typedattr import ( - TypedAttributeProvider, - TypedAttributeSet, - typed_attribute, -) -from ._streams import ByteStream, Listener, UnreliableObjectStream -from ._tasks import TaskGroup - -IPAddressType: TypeAlias = str | IPv4Address | IPv6Address -IPSockAddrType: TypeAlias = tuple[str, int] -SockAddrType: TypeAlias = IPSockAddrType | str -UDPPacketType: TypeAlias = tuple[bytes, IPSockAddrType] -UNIXDatagramPacketType: TypeAlias = tuple[bytes, str] -T_Retval = TypeVar("T_Retval") - - -def _validate_socket( - sock_or_fd: socket.socket | int, - sock_type: socket.SocketKind, - addr_family: socket.AddressFamily = socket.AF_UNSPEC, - *, - require_connected: bool = False, - require_bound: bool = False, -) -> socket.socket: - if isinstance(sock_or_fd, int): - try: - sock = socket.socket(fileno=sock_or_fd) - except OSError as exc: - if exc.errno == errno.ENOTSOCK: - raise ValueError( - "the file descriptor does not refer to a socket" - ) from exc - elif require_connected: - raise ValueError("the socket must be connected") from exc - elif require_bound: - raise ValueError("the socket must be bound to a local address") from exc - else: - raise - elif isinstance(sock_or_fd, socket.socket): - sock = sock_or_fd - else: - raise TypeError( - f"expected an int or socket, got {type(sock_or_fd).__qualname__} instead" - ) - - try: - if require_connected: - try: - sock.getpeername() - except OSError as exc: - raise ValueError("the socket must be connected") from exc - - if require_bound: - try: - if sock.family in (socket.AF_INET, socket.AF_INET6): - bound_addr = sock.getsockname()[1] - else: - bound_addr = sock.getsockname() - except OSError: - bound_addr = None - - if not bound_addr: - raise ValueError("the socket must be bound to a local address") - - if addr_family != socket.AF_UNSPEC and sock.family != addr_family: - raise ValueError( - f"address family mismatch: expected {addr_family.name}, got " - f"{sock.family.name}" - ) - - if sock.type != sock_type: - raise ValueError( - f"socket type mismatch: expected {sock_type.name}, got {sock.type.name}" - ) - except BaseException: - # Avoid ResourceWarning from the locally constructed socket object - if isinstance(sock_or_fd, int): - sock.detach() - - raise - - sock.setblocking(False) - return sock - - -class SocketAttribute(TypedAttributeSet): - """ - .. attribute:: family - :type: socket.AddressFamily - - the address family of the underlying socket - - .. attribute:: local_address - :type: tuple[str, int] | str - - the local address the underlying socket is connected to - - .. attribute:: local_port - :type: int - - for IP based sockets, the local port the underlying socket is bound to - - .. attribute:: raw_socket - :type: socket.socket - - the underlying stdlib socket object - - .. attribute:: remote_address - :type: tuple[str, int] | str - - the remote address the underlying socket is connected to - - .. attribute:: remote_port - :type: int - - for IP based sockets, the remote port the underlying socket is connected to - """ - - family: AddressFamily = typed_attribute() - local_address: SockAddrType = typed_attribute() - local_port: int = typed_attribute() - raw_socket: socket.socket = typed_attribute() - remote_address: SockAddrType = typed_attribute() - remote_port: int = typed_attribute() - - -class _SocketProvider(TypedAttributeProvider): - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - from .._core._sockets import convert_ipv6_sockaddr as convert - - attributes: dict[Any, Callable[[], Any]] = { - SocketAttribute.family: lambda: self._raw_socket.family, - SocketAttribute.local_address: lambda: convert( - self._raw_socket.getsockname() - ), - SocketAttribute.raw_socket: lambda: self._raw_socket, - } - try: - peername: tuple[str, int] | None = convert(self._raw_socket.getpeername()) - except OSError: - peername = None - - # Provide the remote address for connected sockets - if peername is not None: - attributes[SocketAttribute.remote_address] = lambda: peername - - # Provide local and remote ports for IP based sockets - if self._raw_socket.family in (AddressFamily.AF_INET, AddressFamily.AF_INET6): - attributes[SocketAttribute.local_port] = lambda: ( - self._raw_socket.getsockname()[1] - ) - if peername is not None: - remote_port = peername[1] - attributes[SocketAttribute.remote_port] = lambda: remote_port - - return attributes - - @property - @abstractmethod - def _raw_socket(self) -> socket.socket: - pass - - -class SocketStream(ByteStream, _SocketProvider): - """ - Transports bytes over a socket. - - Supports all relevant extra attributes from :class:`~SocketAttribute`. - """ - - @classmethod - async def from_socket(cls, sock_or_fd: socket.socket | int) -> SocketStream: - """ - Wrap an existing socket object or file descriptor as a socket stream. - - The newly created socket wrapper takes ownership of the socket being passed in. - The existing socket must already be connected. - - :param sock_or_fd: a socket object or file descriptor - :return: a socket stream - - """ - sock = _validate_socket(sock_or_fd, socket.SOCK_STREAM, require_connected=True) - return await get_async_backend().wrap_stream_socket(sock) - - -class UNIXSocketStream(SocketStream): - @classmethod - async def from_socket(cls, sock_or_fd: socket.socket | int) -> UNIXSocketStream: - """ - Wrap an existing socket object or file descriptor as a UNIX socket stream. - - The newly created socket wrapper takes ownership of the socket being passed in. - The existing socket must already be connected. - - :param sock_or_fd: a socket object or file descriptor - :return: a UNIX socket stream - - """ - sock = _validate_socket( - sock_or_fd, socket.SOCK_STREAM, socket.AF_UNIX, require_connected=True - ) - return await get_async_backend().wrap_unix_stream_socket(sock) - - @abstractmethod - async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None: - """ - Send file descriptors along with a message to the peer. - - :param message: a non-empty bytestring - :param fds: a collection of files (either numeric file descriptors or open file - or socket objects) - """ - - @abstractmethod - async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]: - """ - Receive file descriptors along with a message from the peer. - - :param msglen: length of the message to expect from the peer - :param maxfds: maximum number of file descriptors to expect from the peer - :return: a tuple of (message, file descriptors) - """ - - -class SocketListener(Listener[SocketStream], _SocketProvider): - """ - Listens to incoming socket connections. - - Supports all relevant extra attributes from :class:`~SocketAttribute`. - """ - - @classmethod - async def from_socket( - cls, - sock_or_fd: socket.socket | int, - ) -> SocketListener: - """ - Wrap an existing socket object or file descriptor as a socket listener. - - The newly created listener takes ownership of the socket being passed in. - - :param sock_or_fd: a socket object or file descriptor - :return: a socket listener - - """ - sock = _validate_socket(sock_or_fd, socket.SOCK_STREAM, require_bound=True) - return await get_async_backend().wrap_listener_socket(sock) - - @abstractmethod - async def accept(self) -> SocketStream: - """Accept an incoming connection.""" - - async def serve( - self, - handler: Callable[[SocketStream], Any], - task_group: TaskGroup | None = None, - ) -> None: - from .. import create_task_group - - async with AsyncExitStack() as stack: - if task_group is None: - task_group = await stack.enter_async_context(create_task_group()) - - while True: - stream = await self.accept() - task_group.start_soon(handler, stream) - - -class UDPSocket(UnreliableObjectStream[UDPPacketType], _SocketProvider): - """ - Represents an unconnected UDP socket. - - Supports all relevant extra attributes from :class:`~SocketAttribute`. - """ - - @classmethod - async def from_socket(cls, sock_or_fd: socket.socket | int) -> UDPSocket: - """ - Wrap an existing socket object or file descriptor as a UDP socket. - - The newly created socket wrapper takes ownership of the socket being passed in. - The existing socket must be bound to a local address. - - :param sock_or_fd: a socket object or file descriptor - :return: a UDP socket - - """ - sock = _validate_socket(sock_or_fd, socket.SOCK_DGRAM, require_bound=True) - return await get_async_backend().wrap_udp_socket(sock) - - async def sendto(self, data: bytes, host: str, port: int) -> None: - """ - Alias for :meth:`~.UnreliableObjectSendStream.send` ((data, (host, port))). - - """ - return await self.send((data, (host, port))) - - -class ConnectedUDPSocket(UnreliableObjectStream[bytes], _SocketProvider): - """ - Represents an connected UDP socket. - - Supports all relevant extra attributes from :class:`~SocketAttribute`. - """ - - @classmethod - async def from_socket(cls, sock_or_fd: socket.socket | int) -> ConnectedUDPSocket: - """ - Wrap an existing socket object or file descriptor as a connected UDP socket. - - The newly created socket wrapper takes ownership of the socket being passed in. - The existing socket must already be connected. - - :param sock_or_fd: a socket object or file descriptor - :return: a connected UDP socket - - """ - sock = _validate_socket( - sock_or_fd, - socket.SOCK_DGRAM, - require_connected=True, - ) - return await get_async_backend().wrap_connected_udp_socket(sock) - - -class UNIXDatagramSocket( - UnreliableObjectStream[UNIXDatagramPacketType], _SocketProvider -): - """ - Represents an unconnected Unix datagram socket. - - Supports all relevant extra attributes from :class:`~SocketAttribute`. - """ - - @classmethod - async def from_socket( - cls, - sock_or_fd: socket.socket | int, - ) -> UNIXDatagramSocket: - """ - Wrap an existing socket object or file descriptor as a UNIX datagram - socket. - - The newly created socket wrapper takes ownership of the socket being passed in. - - :param sock_or_fd: a socket object or file descriptor - :return: a UNIX datagram socket - - """ - sock = _validate_socket(sock_or_fd, socket.SOCK_DGRAM, socket.AF_UNIX) - return await get_async_backend().wrap_unix_datagram_socket(sock) - - async def sendto(self, data: bytes, path: str) -> None: - """Alias for :meth:`~.UnreliableObjectSendStream.send` ((data, path)).""" - return await self.send((data, path)) - - -class ConnectedUNIXDatagramSocket(UnreliableObjectStream[bytes], _SocketProvider): - """ - Represents a connected Unix datagram socket. - - Supports all relevant extra attributes from :class:`~SocketAttribute`. - """ - - @classmethod - async def from_socket( - cls, - sock_or_fd: socket.socket | int, - ) -> ConnectedUNIXDatagramSocket: - """ - Wrap an existing socket object or file descriptor as a connected UNIX datagram - socket. - - The newly created socket wrapper takes ownership of the socket being passed in. - The existing socket must already be connected. - - :param sock_or_fd: a socket object or file descriptor - :return: a connected UNIX datagram socket - - """ - sock = _validate_socket( - sock_or_fd, socket.SOCK_DGRAM, socket.AF_UNIX, require_connected=True - ) - return await get_async_backend().wrap_connected_unix_datagram_socket(sock) diff --git a/server/venv/Lib/site-packages/anyio/abc/_streams.py b/server/venv/Lib/site-packages/anyio/abc/_streams.py deleted file mode 100644 index 186e3f5..0000000 --- a/server/venv/Lib/site-packages/anyio/abc/_streams.py +++ /dev/null @@ -1,233 +0,0 @@ -from __future__ import annotations - -from abc import ABCMeta, abstractmethod -from collections.abc import Callable -from typing import Any, Generic, TypeAlias, TypeVar - -from .._core._exceptions import EndOfStream -from .._core._typedattr import TypedAttributeProvider -from ._resources import AsyncResource -from ._tasks import TaskGroup - -T_Item = TypeVar("T_Item") -T_co = TypeVar("T_co", covariant=True) -T_contra = TypeVar("T_contra", contravariant=True) - - -class UnreliableObjectReceiveStream( - Generic[T_co], AsyncResource, TypedAttributeProvider -): - """ - An interface for receiving objects. - - This interface makes no guarantees that the received messages arrive in the order in - which they were sent, or that no messages are missed. - - Asynchronously iterating over objects of this type will yield objects matching the - given type parameter. - """ - - def __aiter__(self) -> UnreliableObjectReceiveStream[T_co]: - return self - - async def __anext__(self) -> T_co: - try: - return await self.receive() - except EndOfStream: - raise StopAsyncIteration from None - - @abstractmethod - async def receive(self) -> T_co: - """ - Receive the next item. - - :raises ~anyio.ClosedResourceError: if the receive stream has been explicitly - closed - :raises ~anyio.EndOfStream: if this stream has been closed from the other end - :raises ~anyio.BrokenResourceError: if this stream has been rendered unusable - due to external causes - """ - - -class UnreliableObjectSendStream( - Generic[T_contra], AsyncResource, TypedAttributeProvider -): - """ - An interface for sending objects. - - This interface makes no guarantees that the messages sent will reach the - recipient(s) in the same order in which they were sent, or at all. - """ - - @abstractmethod - async def send(self, item: T_contra) -> None: - """ - Send an item to the peer(s). - - :param item: the item to send - :raises ~anyio.ClosedResourceError: if the send stream has been explicitly - closed - :raises ~anyio.BrokenResourceError: if this stream has been rendered unusable - due to external causes - """ - - -class UnreliableObjectStream( - UnreliableObjectReceiveStream[T_Item], UnreliableObjectSendStream[T_Item] -): - """ - A bidirectional message stream which does not guarantee the order or reliability of - message delivery. - """ - - -class ObjectReceiveStream(UnreliableObjectReceiveStream[T_co]): - """ - A receive message stream which guarantees that messages are received in the same - order in which they were sent, and that no messages are missed. - """ - - -class ObjectSendStream(UnreliableObjectSendStream[T_contra]): - """ - A send message stream which guarantees that messages are delivered in the same order - in which they were sent, without missing any messages in the middle. - """ - - -class ObjectStream( - ObjectReceiveStream[T_Item], - ObjectSendStream[T_Item], - UnreliableObjectStream[T_Item], -): - """ - A bidirectional message stream which guarantees the order and reliability of message - delivery. - """ - - @abstractmethod - async def send_eof(self) -> None: - """ - Send an end-of-file indication to the peer. - - You should not try to send any further data to this stream after calling this - method. This method is idempotent (does nothing on successive calls). - """ - - -class ByteReceiveStream(AsyncResource, TypedAttributeProvider): - """ - An interface for receiving bytes from a single peer. - - Iterating this byte stream will yield a byte string of arbitrary length, but no more - than 65536 bytes. - """ - - def __aiter__(self) -> ByteReceiveStream: - return self - - async def __anext__(self) -> bytes: - try: - return await self.receive() - except EndOfStream: - raise StopAsyncIteration from None - - @abstractmethod - async def receive(self, max_bytes: int = 65536) -> bytes: - """ - Receive at most ``max_bytes`` bytes from the peer. - - .. note:: Implementers of this interface should not return an empty - :class:`bytes` object, and users should ignore them. - - :param max_bytes: maximum number of bytes to receive - :return: the received bytes - :raises ~anyio.EndOfStream: if this stream has been closed from the other end - """ - - -class ByteSendStream(AsyncResource, TypedAttributeProvider): - """An interface for sending bytes to a single peer.""" - - @abstractmethod - async def send(self, item: bytes) -> None: - """ - Send the given bytes to the peer. - - :param item: the bytes to send - """ - - -class ByteStream(ByteReceiveStream, ByteSendStream): - """A bidirectional byte stream.""" - - @abstractmethod - async def send_eof(self) -> None: - """ - Send an end-of-file indication to the peer. - - You should not try to send any further data to this stream after calling this - method. This method is idempotent (does nothing on successive calls). - """ - - -#: Type alias for all unreliable bytes-oriented receive streams. -AnyUnreliableByteReceiveStream: TypeAlias = ( - UnreliableObjectReceiveStream[bytes] | ByteReceiveStream -) -#: Type alias for all unreliable bytes-oriented send streams. -AnyUnreliableByteSendStream: TypeAlias = ( - UnreliableObjectSendStream[bytes] | ByteSendStream -) -#: Type alias for all unreliable bytes-oriented streams. -AnyUnreliableByteStream: TypeAlias = UnreliableObjectStream[bytes] | ByteStream -#: Type alias for all bytes-oriented receive streams. -AnyByteReceiveStream: TypeAlias = ObjectReceiveStream[bytes] | ByteReceiveStream -#: Type alias for all bytes-oriented send streams. -AnyByteSendStream: TypeAlias = ObjectSendStream[bytes] | ByteSendStream -#: Type alias for all bytes-oriented streams. -AnyByteStream: TypeAlias = ObjectStream[bytes] | ByteStream - - -class Listener(Generic[T_co], AsyncResource, TypedAttributeProvider): - """An interface for objects that let you accept incoming connections.""" - - @abstractmethod - async def serve( - self, handler: Callable[[T_co], Any], task_group: TaskGroup | None = None - ) -> None: - """ - Accept incoming connections as they come in and start tasks to handle them. - - :param handler: a callable that will be used to handle each accepted connection - :param task_group: the task group that will be used to start tasks for handling - each accepted connection (if omitted, an ad-hoc task group will be created) - """ - - -class ObjectStreamConnectable(Generic[T_co], metaclass=ABCMeta): - @abstractmethod - async def connect(self) -> ObjectStream[T_co]: - """ - Connect to the remote endpoint. - - :return: an object stream connected to the remote end - :raises ConnectionFailed: if the connection fails - """ - - -class ByteStreamConnectable(metaclass=ABCMeta): - @abstractmethod - async def connect(self) -> ByteStream: - """ - Connect to the remote endpoint. - - :return: a bytestream connected to the remote end - :raises ConnectionFailed: if the connection fails - """ - - -#: Type alias for all connectables returning bytestreams or bytes-oriented object streams -AnyByteStreamConnectable: TypeAlias = ( - ObjectStreamConnectable[bytes] | ByteStreamConnectable -) diff --git a/server/venv/Lib/site-packages/anyio/abc/_subprocesses.py b/server/venv/Lib/site-packages/anyio/abc/_subprocesses.py deleted file mode 100644 index ce0564c..0000000 --- a/server/venv/Lib/site-packages/anyio/abc/_subprocesses.py +++ /dev/null @@ -1,79 +0,0 @@ -from __future__ import annotations - -from abc import abstractmethod -from signal import Signals - -from ._resources import AsyncResource -from ._streams import ByteReceiveStream, ByteSendStream - - -class Process(AsyncResource): - """An asynchronous version of :class:`subprocess.Popen`.""" - - @abstractmethod - async def wait(self) -> int: - """ - Wait until the process exits. - - :return: the exit code of the process - """ - - @abstractmethod - def terminate(self) -> None: - """ - Terminates the process, gracefully if possible. - - On Windows, this calls ``TerminateProcess()``. - On POSIX systems, this sends ``SIGTERM`` to the process. - - .. seealso:: :meth:`subprocess.Popen.terminate` - """ - - @abstractmethod - def kill(self) -> None: - """ - Kills the process. - - On Windows, this calls ``TerminateProcess()``. - On POSIX systems, this sends ``SIGKILL`` to the process. - - .. seealso:: :meth:`subprocess.Popen.kill` - """ - - @abstractmethod - def send_signal(self, signal: Signals) -> None: - """ - Send a signal to the subprocess. - - .. seealso:: :meth:`subprocess.Popen.send_signal` - - :param signal: the signal number (e.g. :data:`signal.SIGHUP`) - """ - - @property - @abstractmethod - def pid(self) -> int: - """The process ID of the process.""" - - @property - @abstractmethod - def returncode(self) -> int | None: - """ - The return code of the process. If the process has not yet terminated, this will - be ``None``. - """ - - @property - @abstractmethod - def stdin(self) -> ByteSendStream | None: - """The stream for the standard input of the process.""" - - @property - @abstractmethod - def stdout(self) -> ByteReceiveStream | None: - """The stream for the standard output of the process.""" - - @property - @abstractmethod - def stderr(self) -> ByteReceiveStream | None: - """The stream for the standard error output of the process.""" diff --git a/server/venv/Lib/site-packages/anyio/abc/_tasks.py b/server/venv/Lib/site-packages/anyio/abc/_tasks.py deleted file mode 100644 index 44ee3a7..0000000 --- a/server/venv/Lib/site-packages/anyio/abc/_tasks.py +++ /dev/null @@ -1,209 +0,0 @@ -from __future__ import annotations - -import sys -from abc import ABCMeta, abstractmethod -from collections.abc import Callable, Coroutine -from contextvars import Context -from types import TracebackType -from typing import TYPE_CHECKING, Any, Literal, Protocol, final, overload - -if sys.version_info >= (3, 13): - from typing import TypeVar -else: - from typing_extensions import TypeVar - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -if TYPE_CHECKING: - from .._core._tasks import CancelScope, TaskHandle - -T_co = TypeVar("T_co", covariant=True) -T_contra = TypeVar("T_contra", contravariant=True, default=None) -PosArgsT = TypeVarTuple("PosArgsT") - - -def get_callable_name(func: Callable, override: object = None) -> str: - if override is not None: - return str(override) - - module = getattr(func, "__module__", None) - qualname = getattr(func, "__qualname__", None) - return ".".join([x for x in (module, qualname) if x]) - - -def call_for_coroutine( - func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]], - args: tuple[Unpack[PosArgsT]], - **kwargs: Any, -) -> Coroutine[Any, Any, T_co]: - """ - Call the given function with the given positional and keyword arguments. - - :return: the resulting coroutine - :raises TypeError: if the return value was not a coroutine object - - """ - coro = func(*args, **kwargs) - if not isinstance(coro, Coroutine): - prefix = f"{func.__module__}." if hasattr(func, "__module__") else "" - raise TypeError( - f"Expected {prefix}{func.__qualname__}() to return a coroutine, but " - f"the return value ({coro!r}) is not a coroutine object" - ) - - return coro - - -class TaskStatus(Protocol[T_contra]): - @overload - def started(self: TaskStatus[None]) -> None: ... - - @overload - def started(self, value: T_contra) -> None: ... - - def started(self, value: T_contra | None = None) -> None: - """ - Signal that the task has started. - - :param value: object passed back to the starter of the task - """ - - -class TaskGroup(metaclass=ABCMeta): - """ - Groups several asynchronous tasks together. - - :ivar cancel_scope: the cancel scope inherited by all child tasks - :vartype cancel_scope: CancelScope - - .. note:: On asyncio, support for eager task factories is considered to be - **experimental**. In particular, they don't follow the usual semantics of new - tasks being scheduled on the next iteration of the event loop, and may thus - cause unexpected behavior in code that wasn't written with such semantics in - mind. - """ - - cancel_scope: CancelScope - - def cancel(self, reason: str | None = None) -> None: - """ - Cancel this task group's cancel scope immediately. - - This is a shortcut for calling ``.cancel_scope.cancel()`` on the task group. - - :param reason: a message describing the reason for the cancellation - - .. versionadded:: 4.14.0 - - """ - self.cancel_scope.cancel(reason) - - @abstractmethod - def create_task( - self, - coro: Coroutine[Any, Any, T_co], - *, - name: object = None, - context: Context | None = None, - ) -> TaskHandle[T_co]: - """ - Create a new task from a coroutine object and schedule it to run. - - :param coro: a coroutine object - :param name: optional name to give the task - :param context: optional context to run the task in - :return: a task handle - - .. versionadded:: 4.14.0 - """ - - @final - def start_soon( - self, - func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]], - *args: Unpack[PosArgsT], - name: object = None, - ) -> TaskHandle[T_co]: - """ - Start a new task in this task group. - - :param func: a coroutine function - :param args: positional arguments to call the function with - :param name: name of the task, for the purposes of introspection and debugging - :return: a task handle - - .. versionadded:: 3.0 - .. versionchanged:: 4.14.0 - This method now returns a task handle. - - """ - final_name = get_callable_name(func, name) - return self.create_task(call_for_coroutine(func, args), name=final_name) - - @overload - async def start( - self, - func: Callable[..., Coroutine[Any, Any, T_co]], - *args: object, - name: object = None, - return_handle: Literal[False] = ..., - ) -> Any: ... - - @overload - async def start( - self, - func: Callable[..., Coroutine[Any, Any, T_co]], - *args: object, - name: object = None, - return_handle: Literal[True], - ) -> TaskHandle[T_co, Any]: ... - - @abstractmethod - async def start( - self, - func: Callable[..., Coroutine[Any, Any, T_co]], - *args: object, - name: object = None, - return_handle: Literal[False] | Literal[True] = False, - ) -> Any: - """ - Start a new task and wait until it signals for readiness. - - The target callable must accept a keyword argument ``task_status`` (of type - :class:`TaskStatus`). Awaiting on this method will return whatever was passed to - ``task_status.started()`` (``None`` by default). - - .. note:: The :class:`TaskStatus` class is generic, and the type argument should - indicate the type of the value that will be passed to - ``task_status.started()``. - - :param func: a coroutine function that accepts the ``task_status`` keyword - argument - :param args: positional arguments to call the function with - :param name: an optional name for the task, for introspection and debugging - :param return_handle: if ``True``, return a :class:`TaskHandle` which also - contains the start value in ``start_value`` - :return: the value passed to ``task_status.started()`` - :raises RuntimeError: if the task finishes without calling - ``task_status.started()`` - - .. seealso:: :ref:`start_initialize` - - .. versionadded:: 3.0 - """ - - @abstractmethod - async def __aenter__(self) -> TaskGroup: - """Enter the task group context and allow starting new tasks.""" - - @abstractmethod - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - """Exit the task group context waiting for all tasks to finish.""" diff --git a/server/venv/Lib/site-packages/anyio/abc/_testing.py b/server/venv/Lib/site-packages/anyio/abc/_testing.py deleted file mode 100644 index 2a93fb7..0000000 --- a/server/venv/Lib/site-packages/anyio/abc/_testing.py +++ /dev/null @@ -1,73 +0,0 @@ -from __future__ import annotations - -import types -from abc import ABCMeta, abstractmethod -from collections.abc import AsyncGenerator, Callable, Coroutine, Iterable -from typing import Any, TypeVar - -_T = TypeVar("_T") - - -class TestRunner(metaclass=ABCMeta): - """ - Encapsulates a running event loop. Every call made through this object will use the - same event loop. - """ - - def __enter__(self) -> TestRunner: - return self - - @abstractmethod - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: types.TracebackType | None, - ) -> bool | None: ... - - @abstractmethod - def run_asyncgen_fixture( - self, - fixture_func: Callable[..., AsyncGenerator[_T, Any]], - kwargs: dict[str, Any], - ) -> Iterable[_T]: - """ - Run an async generator fixture. - - :param fixture_func: the fixture function - :param kwargs: keyword arguments to call the fixture function with - :return: an iterator yielding the value yielded from the async generator - """ - - @abstractmethod - def run_fixture( - self, - fixture_func: Callable[..., Coroutine[Any, Any, _T]], - kwargs: dict[str, Any], - ) -> _T: - """ - Run an async fixture. - - :param fixture_func: the fixture function - :param kwargs: keyword arguments to call the fixture function with - :return: the return value of the fixture function - """ - - @abstractmethod - def run_test( - self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any] - ) -> None: - """ - Run an async test function. - - :param test_func: the test function - :param kwargs: keyword arguments to call the test function with - """ - - @abstractmethod - def is_running(self) -> bool: - """ - Check if the test runner is running. - - :return: ``True`` if the coroutine is currently being run, ``False`` otherwise. - """ diff --git a/server/venv/Lib/site-packages/anyio/from_thread.py b/server/venv/Lib/site-packages/anyio/from_thread.py deleted file mode 100644 index 8c7914c..0000000 --- a/server/venv/Lib/site-packages/anyio/from_thread.py +++ /dev/null @@ -1,582 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "BlockingPortal", - "BlockingPortalProvider", - "check_cancelled", - "run", - "run_sync", - "start_blocking_portal", -) - -import sys -from collections.abc import Awaitable, Callable, Coroutine, Generator -from concurrent.futures import Future -from contextlib import ( - AbstractAsyncContextManager, - AbstractContextManager, - contextmanager, -) -from dataclasses import dataclass, field -from functools import partial -from inspect import isawaitable -from threading import Lock, Thread, current_thread, get_ident -from types import TracebackType -from typing import ( - Any, - Generic, - TypeVar, - cast, - overload, -) - -from ._core._eventloop import ( - get_cancelled_exc_class, - threadlocals, -) -from ._core._eventloop import run as run_eventloop -from ._core._exceptions import NoEventLoopError -from ._core._synchronization import Event -from ._core._tasks import CancelScope, create_task_group -from .abc._tasks import TaskStatus -from .lowlevel import EventLoopToken, current_token - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -T_Retval = TypeVar("T_Retval") -T_co = TypeVar("T_co", covariant=True) -PosArgsT = TypeVarTuple("PosArgsT") - - -def _token_or_error(token: EventLoopToken | None) -> EventLoopToken: - if token is not None: - return token - - try: - return threadlocals.current_token - except AttributeError: - raise NoEventLoopError( - "Not running inside an AnyIO worker thread, and no event loop token was " - "provided" - ) from None - - -def run( - func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]], - *args: Unpack[PosArgsT], - token: EventLoopToken | None = None, -) -> T_co: - """ - Call a coroutine function from a worker thread. - - :param func: a coroutine function - :param args: positional arguments for the callable - :param token: an event loop token to use to get back to the event loop thread - (required if calling this function from outside an AnyIO worker thread) - :return: the return value of the coroutine function - :raises MissingTokenError: if no token was provided and called from outside an - AnyIO worker thread - :raises RunFinishedError: if the event loop tied to ``token`` is no longer running - - .. versionchanged:: 4.11.0 - Added the ``token`` parameter. - - """ - explicit_token = token is not None - token = _token_or_error(token) - return token.backend_class.run_async_from_thread( - func, args, token=token.native_token if explicit_token else None - ) - - -def run_sync( - func: Callable[[Unpack[PosArgsT]], T_Retval], - *args: Unpack[PosArgsT], - token: EventLoopToken | None = None, -) -> T_Retval: - """ - Call a function in the event loop thread from a worker thread. - - :param func: a callable - :param args: positional arguments for the callable - :param token: an event loop token to use to get back to the event loop thread - (required if calling this function from outside an AnyIO worker thread) - :return: the return value of the callable - :raises MissingTokenError: if no token was provided and called from outside an - AnyIO worker thread - :raises RunFinishedError: if the event loop tied to ``token`` is no longer running - - .. versionchanged:: 4.11.0 - Added the ``token`` parameter. - - """ - explicit_token = token is not None - token = _token_or_error(token) - return token.backend_class.run_sync_from_thread( - func, args, token=token.native_token if explicit_token else None - ) - - -class _BlockingAsyncContextManager(Generic[T_co], AbstractContextManager): - _enter_future: Future[T_co] - _exit_future: Future[bool | None] - _exit_event: Event - _exit_exc_info: tuple[ - type[BaseException] | None, BaseException | None, TracebackType | None - ] = (None, None, None) - - def __init__( - self, async_cm: AbstractAsyncContextManager[T_co], portal: BlockingPortal - ): - self._async_cm = async_cm - self._portal = portal - - async def run_async_cm(self) -> bool | None: - try: - self._exit_event = Event() - value = await self._async_cm.__aenter__() - except BaseException as exc: - self._enter_future.set_exception(exc) - raise - else: - self._enter_future.set_result(value) - - try: - # Wait for the sync context manager to exit. - # This next statement can raise `get_cancelled_exc_class()` if - # something went wrong in a task group in this async context - # manager. - await self._exit_event.wait() - finally: - # In case of cancellation, it could be that we end up here before - # `_BlockingAsyncContextManager.__exit__` is called, and an - # `_exit_exc_info` has been set. - result = await self._async_cm.__aexit__(*self._exit_exc_info) - - return result - - def __enter__(self) -> T_co: - self._enter_future = Future() - self._exit_future = self._portal.start_task_soon(self.run_async_cm) - return self._enter_future.result() - - def __exit__( - self, - __exc_type: type[BaseException] | None, - __exc_value: BaseException | None, - __traceback: TracebackType | None, - ) -> bool | None: - self._exit_exc_info = __exc_type, __exc_value, __traceback - self._portal.call(self._exit_event.set) - return self._exit_future.result() - - -class _BlockingPortalTaskStatus(TaskStatus): - def __init__(self, future: Future): - self._future = future - - def started(self, value: object = None) -> None: - self._future.set_result(value) - - -class BlockingPortal: - """ - An object that lets external threads run code in an asynchronous event loop. - - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - """ - - def __init__(self) -> None: - self._token = current_token() - self._event_loop_thread_id: int | None = get_ident() - self._stop_event = Event() - self._task_group = create_task_group() - - async def __aenter__(self) -> BlockingPortal: - await self._task_group.__aenter__() - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - await self.stop() - return await self._task_group.__aexit__(exc_type, exc_val, exc_tb) - - def _check_running(self) -> None: - if self._event_loop_thread_id is None: - raise RuntimeError("This portal is not running") - if self._event_loop_thread_id == get_ident(): - raise RuntimeError( - "This method cannot be called from the event loop thread" - ) - - async def sleep_until_stopped(self) -> None: - """Sleep until :meth:`stop` is called.""" - await self._stop_event.wait() - - async def stop(self, cancel_remaining: bool = False) -> None: - """ - Signal the portal to shut down. - - This marks the portal as no longer accepting new calls and exits from - :meth:`sleep_until_stopped`. - - :param cancel_remaining: ``True`` to cancel all the remaining tasks, ``False`` - to let them finish before returning - - """ - self._event_loop_thread_id = None - self._stop_event.set() - if cancel_remaining: - self._task_group.cancel_scope.cancel("the blocking portal is shutting down") - - async def _call_func( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval], - args: tuple[Unpack[PosArgsT]], - kwargs: dict[str, Any], - future: Future[T_Retval], - ) -> None: - event_loop_thread_id = self._event_loop_thread_id - - def callback(f: Future[T_Retval]) -> None: - if f.cancelled(): - if event_loop_thread_id == get_ident(): - scope.cancel("the future was cancelled") - elif event_loop_thread_id is not None: - run_sync( - scope.cancel, "the future was cancelled", token=self._token - ) - - try: - retval_or_awaitable = func(*args, **kwargs) - if isawaitable(retval_or_awaitable): - with CancelScope() as scope: - future.add_done_callback(callback) - retval = await retval_or_awaitable - else: - retval = retval_or_awaitable - except get_cancelled_exc_class(): - future.cancel() - future.set_running_or_notify_cancel() - except BaseException as exc: - if not future.cancelled(): - future.set_exception(exc) - - # Let base exceptions fall through - if not isinstance(exc, Exception): - raise - else: - if not future.cancelled(): - future.set_result(retval) - finally: - scope = None # type: ignore[assignment] - - def _spawn_task_from_thread( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval], - args: tuple[Unpack[PosArgsT]], - kwargs: dict[str, Any], - name: object, - future: Future[T_Retval], - ) -> None: - """ - Spawn a new task using the given callable. - - :param func: a callable - :param args: positional arguments to be passed to the callable - :param kwargs: keyword arguments to be passed to the callable - :param name: name of the task (will be coerced to a string if not ``None``) - :param future: a future that will resolve to the return value of the callable, - or the exception raised during its execution - - """ - run_sync( - partial(self._task_group.start_soon, name=name), - self._call_func, - func, - args, - kwargs, - future, - token=self._token, - ) - - @overload - def call( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - *args: Unpack[PosArgsT], - ) -> T_Retval: ... - - @overload - def call( - self, func: Callable[[Unpack[PosArgsT]], T_Retval], *args: Unpack[PosArgsT] - ) -> T_Retval: ... - - def call( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval], - *args: Unpack[PosArgsT], - ) -> T_Retval: - """ - Call the given function in the event loop thread. - - If the callable returns a coroutine object, it is awaited on. - - :param func: any callable - :raises RuntimeError: if the portal is not running or if this method is called - from within the event loop thread - - """ - return cast(T_Retval, self.start_task_soon(func, *args).result()) - - @overload - def start_task_soon( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - *args: Unpack[PosArgsT], - name: object = None, - ) -> Future[T_Retval]: ... - - @overload - def start_task_soon( - self, - func: Callable[[Unpack[PosArgsT]], T_Retval], - *args: Unpack[PosArgsT], - name: object = None, - ) -> Future[T_Retval]: ... - - def start_task_soon( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval], - *args: Unpack[PosArgsT], - name: object = None, - ) -> Future[T_Retval]: - """ - Start a task in the portal's task group. - - The task will be run inside a cancel scope which can be cancelled by cancelling - the returned future. - - :param func: the target function - :param args: positional arguments passed to ``func`` - :param name: name of the task (will be coerced to a string if not ``None``) - :return: a future that resolves with the return value of the callable if the - task completes successfully, or with the exception raised in the task - :raises RuntimeError: if the portal is not running or if this method is called - from within the event loop thread - :rtype: concurrent.futures.Future[T_Retval] - - .. versionadded:: 3.0 - - """ - self._check_running() - f: Future[T_Retval] = Future() - self._spawn_task_from_thread(func, args, {}, name, f) - return f - - def start_task( - self, - func: Callable[..., Awaitable[T_Retval]], - *args: object, - name: object = None, - ) -> tuple[Future[T_Retval], Any]: - """ - Start a task in the portal's task group and wait until it signals for readiness. - - This method works the same way as :meth:`.abc.TaskGroup.start`. - - :param func: the target function - :param args: positional arguments passed to ``func`` - :param name: name of the task (will be coerced to a string if not ``None``) - :return: a tuple of (future, task_status_value) where the ``task_status_value`` - is the value passed to ``task_status.started()`` from within the target - function - :rtype: tuple[concurrent.futures.Future[T_Retval], Any] - - .. versionadded:: 3.0 - - """ - - def task_done(future: Future[T_Retval]) -> None: - if not task_status_future.done(): - if future.cancelled(): - task_status_future.cancel() - elif future.exception(): - task_status_future.set_exception(future.exception()) - else: - exc = RuntimeError( - "Task exited without calling task_status.started()" - ) - task_status_future.set_exception(exc) - - self._check_running() - task_status_future: Future = Future() - task_status = _BlockingPortalTaskStatus(task_status_future) - f: Future = Future() - f.add_done_callback(task_done) - self._spawn_task_from_thread(func, args, {"task_status": task_status}, name, f) - return f, task_status_future.result() - - def wrap_async_context_manager( - self, cm: AbstractAsyncContextManager[T_co] - ) -> AbstractContextManager[T_co]: - """ - Wrap an async context manager as a synchronous context manager via this portal. - - Spawns a task that will call both ``__aenter__()`` and ``__aexit__()``, stopping - in the middle until the synchronous context manager exits. - - :param cm: an asynchronous context manager - :return: a synchronous context manager - - .. versionadded:: 2.1 - - """ - return _BlockingAsyncContextManager(cm, self) - - -@dataclass -class BlockingPortalProvider: - """ - A manager for a blocking portal. Used as a context manager. The first thread to - enter this context manager causes a blocking portal to be started with the specific - parameters, and the last thread to exit causes the portal to be shut down. Thus, - there will be exactly one blocking portal running in this context as long as at - least one thread has entered this context manager. - - The parameters are the same as for :func:`~anyio.run`. - - :param backend: name of the backend - :param backend_options: backend options - - .. versionadded:: 4.4 - """ - - backend: str = "asyncio" - backend_options: dict[str, Any] | None = None - _lock: Lock = field(init=False, default_factory=Lock) - _leases: int = field(init=False, default=0) - _portal: BlockingPortal = field(init=False) - _portal_cm: AbstractContextManager[BlockingPortal] | None = field( - init=False, default=None - ) - - def __enter__(self) -> BlockingPortal: - with self._lock: - if self._portal_cm is None: - self._portal_cm = start_blocking_portal( - self.backend, self.backend_options - ) - self._portal = self._portal_cm.__enter__() - - self._leases += 1 - return self._portal - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - portal_cm: AbstractContextManager[BlockingPortal] | None = None - with self._lock: - assert self._portal_cm - assert self._leases > 0 - self._leases -= 1 - if not self._leases: - portal_cm = self._portal_cm - self._portal_cm = None - del self._portal - - if portal_cm: - portal_cm.__exit__(None, None, None) - - -@contextmanager -def start_blocking_portal( - backend: str = "asyncio", - backend_options: dict[str, Any] | None = None, - *, - name: str | None = None, -) -> Generator[BlockingPortal, Any, None]: - """ - Start a new event loop in a new thread and run a blocking portal in its main task. - - The parameters are the same as for :func:`~anyio.run`. - - :param backend: name of the backend - :param backend_options: backend options - :param name: name of the thread - :return: a context manager that yields a blocking portal - - .. versionchanged:: 3.0 - Usage as a context manager is now required. - - """ - - async def run_portal() -> None: - async with BlockingPortal() as portal_: - if name is None: - current_thread().name = f"{backend}-portal-{id(portal_):x}" - - future.set_result(portal_) - await portal_.sleep_until_stopped() - - def run_blocking_portal() -> None: - if future.set_running_or_notify_cancel(): - try: - run_eventloop( - run_portal, backend=backend, backend_options=backend_options - ) - except BaseException as exc: - if not future.done(): - future.set_exception(exc) - - future: Future[BlockingPortal] = Future() - thread = Thread(target=run_blocking_portal, daemon=True, name=name) - thread.start() - try: - cancel_remaining_tasks = False - portal = future.result() - try: - yield portal - except BaseException: - cancel_remaining_tasks = True - raise - finally: - try: - portal.call(portal.stop, cancel_remaining_tasks) - except RuntimeError: - pass - finally: - thread.join() - - -def check_cancelled() -> None: - """ - Check if the cancel scope of the host task's running the current worker thread has - been cancelled. - - If the host task's current cancel scope has indeed been cancelled, the - backend-specific cancellation exception will be raised. - - :raises RuntimeError: if the current thread was not spawned by - :func:`.to_thread.run_sync` - - """ - try: - token: EventLoopToken = threadlocals.current_token - except AttributeError: - raise NoEventLoopError( - "This function can only be called inside an AnyIO worker thread" - ) from None - - token.backend_class.check_cancelled() diff --git a/server/venv/Lib/site-packages/anyio/functools.py b/server/venv/Lib/site-packages/anyio/functools.py deleted file mode 100644 index b0bdfb4..0000000 --- a/server/venv/Lib/site-packages/anyio/functools.py +++ /dev/null @@ -1,400 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "AsyncCacheInfo", - "AsyncCacheParameters", - "AsyncLRUCacheWrapper", - "cache", - "lru_cache", - "reduce", -) - -import functools -from collections import OrderedDict -from collections.abc import ( - AsyncIterable, - Awaitable, - Callable, - Coroutine, - Hashable, - Iterable, -) -from functools import update_wrapper -from inspect import iscoroutinefunction -from typing import ( - Any, - Generic, - NamedTuple, - ParamSpec, - TypedDict, - TypeVar, - cast, - final, - overload, -) -from weakref import WeakKeyDictionary - -from ._core._eventloop import current_time -from ._core._synchronization import Lock -from .lowlevel import RunVar, checkpoint - -T = TypeVar("T") -S = TypeVar("S") -P = ParamSpec("P") -lru_cache_items: RunVar[ - WeakKeyDictionary[ - AsyncLRUCacheWrapper[Any, Any], - OrderedDict[ - Hashable, - tuple[_InitialMissingType, Lock, float | None] - | tuple[Any, None, float | None], - ], - ] -] = RunVar("lru_cache_items") - - -class _InitialMissingType: - pass - - -initial_missing: _InitialMissingType = _InitialMissingType() - - -class AsyncCacheInfo(NamedTuple): - hits: int - misses: int - maxsize: int | None - currsize: int - ttl: int | None - - -class AsyncCacheParameters(TypedDict): - maxsize: int | None - typed: bool - always_checkpoint: bool - ttl: int | None - - -class _LRUMethodWrapper(Generic[T]): - def __init__(self, wrapper: AsyncLRUCacheWrapper[..., T], instance: object): - self.__wrapper = wrapper - self.__instance = instance - - def cache_info(self) -> AsyncCacheInfo: - return self.__wrapper.cache_info() - - def cache_parameters(self) -> AsyncCacheParameters: - return self.__wrapper.cache_parameters() - - def cache_clear(self) -> None: - self.__wrapper.cache_clear() - - async def __call__(self, *args: Any, **kwargs: Any) -> T: - if self.__instance is None: - return await self.__wrapper(*args, **kwargs) - - return await self.__wrapper(self.__instance, *args, **kwargs) - - -@final -class AsyncLRUCacheWrapper(Generic[P, T]): - def __init__( - self, - func: Callable[P, Awaitable[T]], - maxsize: int | None, - typed: bool, - always_checkpoint: bool, - ttl: int | None, - ): - self.__wrapped__ = func - self._hits: int = 0 - self._misses: int = 0 - self._maxsize = max(maxsize, 0) if maxsize is not None else None - self._currsize: int = 0 - self._typed = typed - self._always_checkpoint = always_checkpoint - self._ttl = ttl - update_wrapper(self, func) - - def cache_info(self) -> AsyncCacheInfo: - return AsyncCacheInfo( - self._hits, self._misses, self._maxsize, self._currsize, self._ttl - ) - - def cache_parameters(self) -> AsyncCacheParameters: - return { - "maxsize": self._maxsize, - "typed": self._typed, - "always_checkpoint": self._always_checkpoint, - "ttl": self._ttl, - } - - def cache_clear(self) -> None: - if cache := lru_cache_items.get(None): - cache.pop(self, None) - self._hits = self._misses = self._currsize = 0 - - async def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T: - # Easy case first: if maxsize == 0, no caching is done - if self._maxsize == 0: - value = await self.__wrapped__(*args, **kwargs) - self._misses += 1 - return value - - # The key is constructed as a flat tuple to avoid memory overhead - key: tuple[Any, ...] = args - if kwargs: - # initial_missing is used as a separator - key += (initial_missing,) + sum(kwargs.items(), ()) - - if self._typed: - key += tuple(type(arg) for arg in args) - if kwargs: - key += (initial_missing,) + tuple(type(val) for val in kwargs.values()) - - try: - cache = lru_cache_items.get() - except LookupError: - cache = WeakKeyDictionary() - lru_cache_items.set(cache) - - try: - cache_entry = cache[self] - except KeyError: - cache_entry = cache[self] = OrderedDict() - - cached_value: T | _InitialMissingType - try: - cached_value, lock, expires_at = cache_entry[key] - except KeyError: - # We're the first task to call this function - cached_value, lock, expires_at = ( - initial_missing, - Lock(fast_acquire=not self._always_checkpoint), - None, - ) - cache_entry[key] = cached_value, lock, expires_at - - if lock is None: - if expires_at is not None and current_time() >= expires_at: - self._currsize -= 1 - cached_value, lock, expires_at = ( - initial_missing, - Lock(fast_acquire=not self._always_checkpoint), - None, - ) - cache_entry[key] = cached_value, lock, expires_at - else: - # The value was already cached - self._hits += 1 - cache_entry.move_to_end(key) - if self._always_checkpoint: - await checkpoint() - - return cast(T, cached_value) - - async with lock: - # Check if another task filled the cache while we acquired the lock - if (cached_value := cache_entry[key][0]) is initial_missing: - self._misses += 1 - if self._maxsize is not None and self._currsize >= self._maxsize: - cache_entry.popitem(last=False) - else: - self._currsize += 1 - - value = await self.__wrapped__(*args, **kwargs) - expires_at = ( - current_time() + self._ttl if self._ttl is not None else None - ) - cache_entry[key] = value, None, expires_at - else: - # Another task filled the cache while we were waiting for the lock - self._hits += 1 - cache_entry.move_to_end(key) - value = cast(T, cached_value) - - return value - - def __get__( - self, instance: object, owner: type | None = None - ) -> _LRUMethodWrapper[T]: - wrapper = _LRUMethodWrapper(self, instance) - update_wrapper(wrapper, self.__wrapped__) - return wrapper - - -class _LRUCacheWrapper: - def __init__( - self, maxsize: int | None, typed: bool, always_checkpoint: bool, ttl: int | None - ): - self._maxsize = maxsize - self._typed = typed - self._always_checkpoint = always_checkpoint - self._ttl = ttl - - @overload - def __call__( # type: ignore[overload-overlap] - self, func: Callable[P, Coroutine[Any, Any, T]], / - ) -> AsyncLRUCacheWrapper[P, T]: ... - - @overload - def __call__( - self, func: Callable[..., T], / - ) -> functools._lru_cache_wrapper[T]: ... - - def __call__( - self, f: Callable[P, Coroutine[Any, Any, T]] | Callable[..., T], / - ) -> AsyncLRUCacheWrapper[P, T] | functools._lru_cache_wrapper[T]: - if iscoroutinefunction(f): - return AsyncLRUCacheWrapper( - f, self._maxsize, self._typed, self._always_checkpoint, self._ttl - ) - - return functools.lru_cache(maxsize=self._maxsize, typed=self._typed)(f) # type: ignore[arg-type] - - -@overload -def cache( # type: ignore[overload-overlap] - func: Callable[P, Coroutine[Any, Any, T]], / -) -> AsyncLRUCacheWrapper[P, T]: ... - - -@overload -def cache(func: Callable[..., T], /) -> functools._lru_cache_wrapper[T]: ... - - -def cache(func: Callable[..., Any] | Callable[P, Coroutine[Any, Any, Any]], /) -> Any: - """ - A convenient shortcut for :func:`lru_cache` with ``maxsize=None``. - - This is the asynchronous equivalent to :func:`functools.cache`. - - """ - return lru_cache(maxsize=None)(func) - - -@overload -def lru_cache( - *, - maxsize: int | None = ..., - typed: bool = ..., - always_checkpoint: bool = ..., - ttl: int | None = ..., -) -> _LRUCacheWrapper: ... - - -@overload -def lru_cache( # type: ignore[overload-overlap] - func: Callable[P, Coroutine[Any, Any, T]], / -) -> AsyncLRUCacheWrapper[P, T]: ... - - -@overload -def lru_cache(func: Callable[..., T], /) -> functools._lru_cache_wrapper[T]: ... - - -def lru_cache( - func: Callable[..., Coroutine[Any, Any, Any]] | Callable[..., Any] | None = None, - /, - *, - maxsize: int | None = 128, - typed: bool = False, - always_checkpoint: bool = False, - ttl: int | None = None, -) -> Any: - """ - An asynchronous version of :func:`functools.lru_cache`. - - If a synchronous function is passed, the standard library - :func:`functools.lru_cache` is applied instead. - - :param always_checkpoint: if ``True``, every call to the cached function will be - guaranteed to yield control to the event loop at least once - :param ttl: time in seconds after which to invalidate cache entries - - .. note:: Caches and locks are managed on a per-event loop basis. - - """ - if func is None: - return _LRUCacheWrapper(maxsize, typed, always_checkpoint, ttl) - - if not callable(func): - raise TypeError("the first argument must be callable") - - return _LRUCacheWrapper(maxsize, typed, always_checkpoint, ttl)(func) - - -@overload -async def reduce( - function: Callable[[T, S], Awaitable[T]], - iterable: Iterable[S] | AsyncIterable[S], - /, - initial: T, -) -> T: ... - - -@overload -async def reduce( - function: Callable[[T, T], Awaitable[T]], - iterable: Iterable[T] | AsyncIterable[T], - /, -) -> T: ... - - -async def reduce( # type: ignore[misc] - function: Callable[[T, T], Awaitable[T]] | Callable[[T, S], Awaitable[T]], - iterable: Iterable[T] | Iterable[S] | AsyncIterable[T] | AsyncIterable[S], - /, - initial: T | _InitialMissingType = initial_missing, -) -> T: - """ - Asynchronous version of :func:`functools.reduce`. - - :param function: a coroutine function that takes two arguments: the accumulated - value and the next element from the iterable - :param iterable: an iterable or async iterable - :param initial: the initial value (if missing, the first element of the iterable is - used as the initial value) - - """ - element: Any - function_called = False - if isinstance(iterable, AsyncIterable): - async_it = iterable.__aiter__() - if initial is initial_missing: - try: - value = cast(T, await async_it.__anext__()) - except StopAsyncIteration: - raise TypeError( - "reduce() of empty sequence with no initial value" - ) from None - else: - value = cast(T, initial) - - async for element in async_it: - value = await function(value, element) - function_called = True - elif isinstance(iterable, Iterable): - it = iter(iterable) - if initial is initial_missing: - try: - value = cast(T, next(it)) - except StopIteration: - raise TypeError( - "reduce() of empty sequence with no initial value" - ) from None - else: - value = cast(T, initial) - - for element in it: - value = await function(value, element) - function_called = True - else: - raise TypeError("reduce() argument 2 must be an iterable or async iterable") - - # Make sure there is at least one checkpoint, even if an empty iterable and an - # initial value were given - if not function_called: - await checkpoint() - - return value diff --git a/server/venv/Lib/site-packages/anyio/itertools.py b/server/venv/Lib/site-packages/anyio/itertools.py deleted file mode 100644 index 7e5248e..0000000 --- a/server/venv/Lib/site-packages/anyio/itertools.py +++ /dev/null @@ -1,626 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "accumulate", - "batched", - "Chain", - "combinations", - "combinations_with_replacement", - "compress", - "count", - "cycle", - "dropwhile", - "filterfalse", - "groupby", - "islice", - "pairwise", - "permutations", - "product", - "repeat", - "starmap", - "tee", - "takewhile", - "zip_longest", -) - -import itertools -import operator -import sys -from collections.abc import ( - AsyncGenerator, - AsyncIterable, - AsyncIterator, - Awaitable, - Callable, - Iterable, - Iterator, -) -from dataclasses import dataclass, field -from typing import Any, Generic, TypeVar, cast, overload - -from ._core._synchronization import Lock -from ._core._tasks import CancelScope -from .lowlevel import cancel_shielded_checkpoint, checkpoint, checkpoint_if_cancelled - -T = TypeVar("T") -R = TypeVar("R") -_tee_end = object() - - -@dataclass(eq=False) -class _IterableAsyncIterator(AsyncIterator[T]): - iterator: Iterator[T] - - async def __anext__(self) -> T: - await checkpoint_if_cancelled() - try: - result = next(self.iterator) - except StopIteration: - await cancel_shielded_checkpoint() - raise StopAsyncIteration from None - - await cancel_shielded_checkpoint() - return result - - -def _iterate(iterable: Iterable[T] | AsyncIterable[T]) -> AsyncIterator[T]: - if isinstance(iterable, AsyncIterator): - return iterable - - if isinstance(iterable, AsyncIterable): - return iterable.__aiter__() - - return _IterableAsyncIterator(iter(iterable)) - - -@dataclass(eq=False) -class _TeeLink(Generic[T]): - value: object | None = None - next: _TeeLink[T] | None = None - filled: bool = False - - -@dataclass(eq=False) -class _TeeState(Generic[T]): - iterator: AsyncIterator[T] - lock: Lock = field(default_factory=Lock) - - async def fill(self, link: _TeeLink[T]) -> bool: - if link.filled: - return False - - async with self.lock: - if link.filled: - return True - - link.value = await anext(self.iterator, _tee_end) - if link.value is not _tee_end: - link.next = _TeeLink() - - link.filled = True - return True - - -class _TeeAsyncIterator(AsyncIterator[T]): - _state: _TeeState[T] - _link: _TeeLink[T] - _element_yielded: bool - - def __init__( - self, iterable: Iterable[T] | AsyncIterable[T] | _TeeAsyncIterator[T] - ) -> None: - if isinstance(iterable, _TeeAsyncIterator): - self._state = iterable._state - self._link = iterable._link - else: - self._state = _TeeState(_iterate(iterable)) - self._link = _TeeLink() - - self._element_yielded = False - - async def __anext__(self) -> T: - had_yieldpoint = await self._state.fill(self._link) - if self._link.value is _tee_end: - if not self._element_yielded: - await checkpoint() - - raise StopAsyncIteration - - if not had_yieldpoint: - await checkpoint_if_cancelled() - - self._element_yielded = True - value = cast(T, self._link.value) - next_link = self._link.next - assert next_link is not None - self._link = next_link - if not had_yieldpoint: - await cancel_shielded_checkpoint() - - return value - - -async def _operator_add(x: T, y: T) -> T: - return operator.add(x, y) - - -async def accumulate( - iterable: Iterable[T] | AsyncIterable[T], - function: Callable[[T, T], Awaitable[T]] = _operator_add, - *, - initial: T | None = None, -) -> AsyncGenerator[T, None]: - iterator = _iterate(iterable) - if initial is None: - try: - total = await anext(iterator) - except StopAsyncIteration: - await checkpoint() - return - else: - await checkpoint_if_cancelled() - total = initial - await cancel_shielded_checkpoint() - - yield total - - async for element in iterator: - total = await function(total, element) - yield total - - -async def batched( - iterable: Iterable[T] | AsyncIterable[T], n: int, *, strict: bool = False -) -> AsyncGenerator[tuple[T, ...], None]: - if n < 1: - raise ValueError("n must be at least one") - - iterator = _iterate(iterable) - - while True: - batch: list[T] = [] - for _ in range(n): - try: - batch.append(await anext(iterator)) - except StopAsyncIteration: - if not batch: - await checkpoint() - return - if strict: - raise ValueError("batched(): incomplete batch") from None - - yield tuple(batch) - return - - yield tuple(batch) - - -class Chain: - def __call__( - self, *iterables: Iterable[T] | AsyncIterable[T] - ) -> AsyncGenerator[T, None]: - return self.from_iterable(iterables) - - async def from_iterable( - self, - iterables: ( - Iterable[Iterable[T] | AsyncIterable[T]] - | AsyncIterable[Iterable[T] | AsyncIterable[T]] - ), - ) -> AsyncGenerator[T, None]: - element_yielded = False - outer_iter = _iterate(iterables) - - try: - async for iterable in outer_iter: - async for element in _iterate(iterable): - element_yielded = True - yield element - finally: - aclose = getattr(outer_iter, "aclose", None) - if aclose is not None: - with CancelScope(shield=True): - await aclose() - - if not element_yielded: - await checkpoint() - - -chain: Chain = Chain() - - -async def combinations( - iterable: Iterable[T] | AsyncIterable[T], r: int -) -> AsyncGenerator[tuple[T, ...], None]: - pool: list[T] = [element async for element in _iterate(iterable)] - async for combination in _iterate(itertools.combinations(pool, r)): - yield combination - - -async def combinations_with_replacement( - iterable: Iterable[T] | AsyncIterable[T], r: int -) -> AsyncGenerator[tuple[T, ...], None]: - pool: list[T] = [element async for element in _iterate(iterable)] - async for combination in _iterate(itertools.combinations_with_replacement(pool, r)): - yield combination - - -async def compress( - data: Iterable[T] | AsyncIterable[T], - selectors: Iterable[object] | AsyncIterable[object], -) -> AsyncGenerator[T, None]: - data_iterator = _iterate(data) - selector_iterator = _iterate(selectors) - element_yielded = False - - while True: - try: - datum = await anext(data_iterator) - selector = await anext(selector_iterator) - except StopAsyncIteration: - if not element_yielded: - await checkpoint() - - return - - if selector: - element_yielded = True - yield datum - - -async def count(start: int = 0, step: int = 1) -> AsyncGenerator[int, None]: - n = start - while True: - await checkpoint_if_cancelled() - value = n - n += step - await cancel_shielded_checkpoint() - yield value - - -async def cycle( - iterable: Iterable[T] | AsyncIterable[T], -) -> AsyncGenerator[T, None]: - saved: list[T] = [] - async for element in _iterate(iterable): - saved.append(element) - yield element - - if not saved: - await checkpoint() - return - - while True: - for element in saved: - await checkpoint() - yield element - - -async def dropwhile( - predicate: Callable[[T], Awaitable[object]], - iterable: Iterable[T] | AsyncIterable[T], -) -> AsyncGenerator[T, None]: - element_yielded = False - dropping = True - - async for element in _iterate(iterable): - if dropping and await predicate(element): - continue - - dropping = False - element_yielded = True - yield element - - if not element_yielded: - await checkpoint() - - -async def filterfalse( - predicate: Callable[[T], Awaitable[object]], - iterable: Iterable[T] | AsyncIterable[T], -) -> AsyncGenerator[T, None]: - element_yielded = False - - async for element in _iterate(iterable): - if not await predicate(element): - element_yielded = True - yield element - - if not element_yielded: - await checkpoint() - - -@overload -def groupby( - iterable: Iterable[T] | AsyncIterable[T], -) -> AsyncGenerator[tuple[T, list[T]], None]: ... - - -@overload -def groupby( - iterable: Iterable[T] | AsyncIterable[T], - key: Callable[[T], Awaitable[R]], -) -> AsyncGenerator[tuple[R, list[T]], None]: ... - - -async def groupby( - iterable: Iterable[T] | AsyncIterable[T], - key: Callable[[T], Awaitable[object]] | None = None, -) -> AsyncGenerator[tuple[object, list[T]], None]: - iterator = _iterate(iterable) - try: - element = await anext(iterator) - except StopAsyncIteration: - await checkpoint() - return - - group_key = element if key is None else await key(element) - values = [element] - - async for element in iterator: - next_key = element if key is None else await key(element) - if next_key != group_key: - completed_group = group_key, values - group_key = next_key - values = [element] - yield completed_group - else: - values.append(element) - - yield group_key, values - - -@overload -def islice( - iterable: Iterable[T] | AsyncIterable[T], - stop: int | None, - /, -) -> AsyncGenerator[T, None]: ... - - -@overload -def islice( - iterable: Iterable[T] | AsyncIterable[T], - start: int | None, - stop: int | None, - step: int | None = 1, - /, -) -> AsyncGenerator[T, None]: ... - - -async def islice( - iterable: Iterable[T] | AsyncIterable[T], - *args: int | None, -) -> AsyncGenerator[T, None]: - if not args: - raise TypeError("islice expected at least 2 arguments, got 1") - if len(args) > 3: - raise TypeError(f"islice expected at most 4 arguments, got {len(args) + 1}") - - slice_args = slice(*args) - - start_message = ( - "Indices for islice() must be None or an integer: 0 <= x <= sys.maxsize." - ) - stop_message = ( - "Stop argument for islice() must be None or an integer: 0 <= x <= sys.maxsize." - ) - step_message = "Step for islice() must be a positive integer or None." - - def normalize_index(value: object, message: str) -> int: - try: - index = operator.index(cast(Any, value)) - except TypeError: - raise ValueError(message) from None - - if index < 0 or index > sys.maxsize: - raise ValueError(message) - - return index - - start = ( - 0 - if slice_args.start is None - else normalize_index(slice_args.start, start_message) - ) - stop = ( - None - if slice_args.stop is None - else normalize_index(slice_args.stop, stop_message) - ) - step = ( - 1 if slice_args.step is None else normalize_index(slice_args.step, step_message) - ) - - if step <= 0: - raise ValueError(step_message) - - if stop == 0 or start == stop: - await checkpoint() - return - - iterator = _iterate(iterable) - index = 0 - element_yielded = False - - while stop is None or index < stop: - try: - element = await anext(iterator) - except StopAsyncIteration: - if not element_yielded: - await checkpoint() - - return - - if index >= start and (index - start) % step == 0: - index += 1 - element_yielded = True - yield element - else: - index += 1 - - if not element_yielded: - await checkpoint() - - -async def pairwise( - iterable: Iterable[T] | AsyncIterable[T], -) -> AsyncGenerator[tuple[T, T], None]: - iterator = _iterate(iterable) - try: - previous = await anext(iterator) - except StopAsyncIteration: - await checkpoint() - return - - element_yielded = False - async for element in iterator: - element_yielded = True - pair = (previous, element) - previous = element - yield pair - - if not element_yielded: - await checkpoint() - - -async def permutations( - iterable: Iterable[T] | AsyncIterable[T], r: int | None = None -) -> AsyncGenerator[tuple[T, ...], None]: - pool: list[T] = [element async for element in _iterate(iterable)] - n = len(pool) - if r is None: - r = n - elif not isinstance(r, int): - raise TypeError("Expected int as r") - elif r < 0: - raise ValueError("r must be non-negative") - - async for permutation in _iterate(itertools.permutations(pool, r)): - yield permutation - - -async def product( - *iterables: Iterable[T] | AsyncIterable[T], repeat: int = 1 -) -> AsyncGenerator[tuple[T, ...], None]: - repeat = operator.index(repeat) - if repeat < 0: - raise ValueError("repeat argument cannot be negative") - - pools: list[tuple[T, ...]] = [] - for iterable in iterables: - pool: list[T] = [element async for element in _iterate(iterable)] - pools.append(tuple(pool)) - - async for value in _iterate(itertools.product(*pools, repeat=repeat)): - yield value - - -async def repeat(element: T, times: int | None = None) -> AsyncGenerator[T, None]: - if times is None: - while True: - await checkpoint() - yield element - - remaining = operator.index(cast(Any, times)) - if remaining <= 0: - await checkpoint() - return - - while remaining > 0: - await checkpoint_if_cancelled() - remaining -= 1 - await cancel_shielded_checkpoint() - yield element - - -async def starmap( - function: Callable[..., Awaitable[R]], - iterable: ( - Iterable[Iterable[object] | AsyncIterable[object]] - | AsyncIterable[Iterable[object] | AsyncIterable[object]] - ), -) -> AsyncGenerator[R, None]: - result_yielded = False - - async for args_iterable in _iterate(iterable): - args = [element async for element in _iterate(args_iterable)] - result_yielded = True - yield await function(*args) - - if not result_yielded: - await checkpoint() - - -def tee( - iterable: Iterable[T] | AsyncIterable[T], n: int = 2 -) -> tuple[AsyncIterator[T], ...]: - n = operator.index(cast(Any, n)) - if n < 0: - raise ValueError("n must be >= 0") - if n == 0: - return () - - iterator = _TeeAsyncIterator(iterable) - iterators: list[AsyncIterator[T]] = [iterator] - iterators.extend(_TeeAsyncIterator(iterator) for _ in range(n - 1)) - return tuple(iterators) - - -async def takewhile( - predicate: Callable[[T], Awaitable[object]], - iterable: Iterable[T] | AsyncIterable[T], -) -> AsyncGenerator[T, None]: - element_yielded = False - - async for element in _iterate(iterable): - if not await predicate(element): - if not element_yielded: - await checkpoint() - - return - - element_yielded = True - yield element - - if not element_yielded: - await checkpoint() - - -async def zip_longest( - *iterables: Iterable[object] | AsyncIterable[object], - fillvalue: object = None, -) -> AsyncGenerator[tuple[object, ...], None]: - iterators = [_iterate(iterable) for iterable in iterables] - num_active = len(iterators) - if not num_active: - await checkpoint() - return - - active = [True] * num_active - tuple_yielded = False - - while True: - values: list[object] = [] - for index, iterator in enumerate(iterators): - if not active[index]: - values.append(fillvalue) - continue - - try: - value = await anext(iterator) - except StopAsyncIteration: - active[index] = False - num_active -= 1 - if not num_active: - if not tuple_yielded: - await checkpoint() - - return - - value = fillvalue - - values.append(value) - - tuple_yielded = True - yield tuple(values) diff --git a/server/venv/Lib/site-packages/anyio/lowlevel.py b/server/venv/Lib/site-packages/anyio/lowlevel.py deleted file mode 100644 index d045791..0000000 --- a/server/venv/Lib/site-packages/anyio/lowlevel.py +++ /dev/null @@ -1,226 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "EventLoopToken", - "RunvarToken", - "RunVar", - "checkpoint", - "checkpoint_if_cancelled", - "cancel_shielded_checkpoint", - "current_token", -) - -import enum -from dataclasses import dataclass -from types import TracebackType -from typing import Any, Generic, Literal, TypeVar, final, overload -from weakref import WeakKeyDictionary - -from ._core._eventloop import get_async_backend -from .abc import AsyncBackend - -T = TypeVar("T") -D = TypeVar("D") - - -async def checkpoint() -> None: - """ - Check for cancellation and allow the scheduler to switch to another task. - - Equivalent to (but more efficient than):: - - await checkpoint_if_cancelled() - await cancel_shielded_checkpoint() - - .. versionadded:: 3.0 - - """ - await get_async_backend().checkpoint() - - -async def checkpoint_if_cancelled() -> None: - """ - Enter a checkpoint if the enclosing cancel scope has been cancelled. - - This does not allow the scheduler to switch to a different task. - - .. versionadded:: 3.0 - - """ - await get_async_backend().checkpoint_if_cancelled() - - -async def cancel_shielded_checkpoint() -> None: - """ - Allow the scheduler to switch to another task but without checking for cancellation. - - Equivalent to (but potentially more efficient than):: - - with CancelScope(shield=True): - await checkpoint() - - .. versionadded:: 3.0 - - """ - await get_async_backend().cancel_shielded_checkpoint() - - -@final -@dataclass(frozen=True, repr=False) -class EventLoopToken: - """ - An opaque object that holds a reference to an event loop. - - .. versionadded:: 4.11.0 - """ - - backend_class: type[AsyncBackend] - native_token: object - - -def current_token() -> EventLoopToken: - """ - Return a token object that can be used to call code in the current event loop from - another thread. - - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - .. versionadded:: 4.11.0 - - """ - backend_class = get_async_backend() - raw_token = backend_class.current_token() - return EventLoopToken(backend_class, raw_token) - - -_run_vars: WeakKeyDictionary[object, dict[RunVar[Any], Any]] = WeakKeyDictionary() - - -class _NoValueSet(enum.Enum): - NO_VALUE_SET = enum.auto() - - -class RunvarToken(Generic[T]): - """ - A token that can be used to restore a :class:`RunVar` to its previous value. - - Returned by :meth:`RunVar.set`. Can be used as a context manager to automatically - reset the variable on exit, or passed directly to :meth:`RunVar.reset`. - """ - - __slots__ = "_var", "_value", "_redeemed" - - def __init__(self, var: RunVar[T], value: T | Literal[_NoValueSet.NO_VALUE_SET]): - self._var = var - self._value: T | Literal[_NoValueSet.NO_VALUE_SET] = value - self._redeemed = False - - def __enter__(self) -> RunvarToken[T]: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self._var.reset(self) - - -class RunVar(Generic[T]): - """ - Like a :class:`~contextvars.ContextVar`, except scoped to the running event loop. - - Can be used as a context manager, Just like :class:`~contextvars.ContextVar`, that - will reset the variable to its previous value when the context block is exited. - """ - - __slots__ = "_name", "_default" - - NO_VALUE_SET: Literal[_NoValueSet.NO_VALUE_SET] = _NoValueSet.NO_VALUE_SET - - def __init__( - self, name: str, default: T | Literal[_NoValueSet.NO_VALUE_SET] = NO_VALUE_SET - ): - self._name = name - self._default = default - - @property - def _current_vars(self) -> dict[RunVar[T], T]: - native_token = current_token().native_token - try: - return _run_vars[native_token] - except KeyError: - run_vars = _run_vars[native_token] = {} - return run_vars - - @overload - def get(self, default: D) -> T | D: ... - - @overload - def get(self) -> T: ... - - def get( - self, default: D | Literal[_NoValueSet.NO_VALUE_SET] = NO_VALUE_SET - ) -> T | D: - """ - Return the current value of this run variable. - - :param default: a fallback value to return if no value has been set - :return: the current value, the provided default, or the variable's own default - :raises LookupError: if no value is set and no default is available - - """ - try: - return self._current_vars[self] - except KeyError: - if default is not RunVar.NO_VALUE_SET: - return default - elif self._default is not RunVar.NO_VALUE_SET: - return self._default - - raise LookupError( - f'Run variable "{self._name}" has no value and no default set' - ) - - def set(self, value: T) -> RunvarToken[T]: - """ - Set the value of this run variable for the current event loop. - - :param value: the new value - :return: a token that can be used to restore the previous value - - """ - current_vars = self._current_vars - token = RunvarToken(self, current_vars.get(self, RunVar.NO_VALUE_SET)) - current_vars[self] = value - return token - - def reset(self, token: RunvarToken[T]) -> None: - """ - Restore this run variable to the value it held before the matching :meth:`set`. - - :param token: the token returned by :meth:`set` - :raises ValueError: if the token belongs to a different :class:`RunVar` or the token - has already been used - - """ - if token._var is not self: - raise ValueError("This token does not belong to this RunVar") - - if token._redeemed: - raise ValueError("This token has already been used") - - if token._value is _NoValueSet.NO_VALUE_SET: - try: - del self._current_vars[self] - except KeyError: - pass - else: - self._current_vars[self] = token._value - - token._redeemed = True - - def __repr__(self) -> str: - return f"" diff --git a/server/venv/Lib/site-packages/anyio/py.typed b/server/venv/Lib/site-packages/anyio/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/server/venv/Lib/site-packages/anyio/pytest_plugin.py b/server/venv/Lib/site-packages/anyio/pytest_plugin.py deleted file mode 100644 index 5c66759..0000000 --- a/server/venv/Lib/site-packages/anyio/pytest_plugin.py +++ /dev/null @@ -1,375 +0,0 @@ -from __future__ import annotations - -import dataclasses -import socket -import sys -from collections.abc import Callable, Generator, Iterator -from contextlib import ExitStack, contextmanager -from inspect import isasyncgenfunction, iscoroutinefunction, ismethod -from typing import Any, cast - -import pytest -from _pytest.fixtures import FuncFixtureInfo, SubRequest -from _pytest.outcomes import Exit -from _pytest.python import CallSpec2 -from _pytest.scope import Scope - -from . import get_available_backends -from ._core._eventloop import ( - current_async_library, - get_async_backend, - reset_current_async_library, - set_current_async_library, -) -from ._core._exceptions import iterate_exceptions -from .abc import TestRunner - -if sys.version_info < (3, 11): - from exceptiongroup import ExceptionGroup - -_current_runner: TestRunner | None = None -_runner_stack: ExitStack | None = None -_runner_leases = 0 - - -def extract_backend_and_options(backend: object) -> tuple[str, dict[str, Any]]: - if isinstance(backend, str): - return backend, {} - elif isinstance(backend, tuple) and len(backend) == 2: - if isinstance(backend[0], str) and isinstance(backend[1], dict): - return cast(tuple[str, dict[str, Any]], backend) - - raise TypeError("anyio_backend must be either a string or tuple of (string, dict)") - - -@contextmanager -def get_runner( - backend_name: str, backend_options: dict[str, Any] -) -> Iterator[TestRunner]: - global _current_runner, _runner_leases, _runner_stack - if _current_runner is None: - asynclib = get_async_backend(backend_name) - _runner_stack = ExitStack() - if current_async_library() is None: - # Since we're in control of the event loop, we can cache the name of the - # async library - token = set_current_async_library(backend_name) - _runner_stack.callback(reset_current_async_library, token) - - backend_options = backend_options or {} - _current_runner = _runner_stack.enter_context( - asynclib.create_test_runner(backend_options) - ) - - _runner_leases += 1 - try: - yield _current_runner - finally: - _runner_leases -= 1 - if not _runner_leases: - assert _runner_stack is not None - _runner_stack.close() - _runner_stack = _current_runner = None - - -def pytest_addoption(parser: pytest.Parser) -> None: - parser.addini( - "anyio_mode", - default="strict", - help='AnyIO plugin mode (either "strict" or "auto")', - ) - - -def pytest_configure(config: pytest.Config) -> None: - config.addinivalue_line( - "markers", - "anyio: mark the (coroutine function) test to be run asynchronously via anyio.", - ) - if ( - config.getini("anyio_mode") == "auto" - and config.pluginmanager.has_plugin("asyncio") - and config.getini("asyncio_mode") == "auto" - ): - config.issue_config_time_warning( - pytest.PytestConfigWarning( - "AnyIO auto mode has been enabled together with pytest-asyncio auto " - "mode. This may cause unexpected behavior." - ), - 1, - ) - - -@pytest.hookimpl(hookwrapper=True) -def pytest_fixture_setup(fixturedef: Any, request: Any) -> Generator[Any]: - def wrapper(anyio_backend: Any, request: SubRequest, **kwargs: Any) -> Any: - # Rebind any fixture methods to the request instance - if ( - request.instance - and ismethod(func) - and type(func.__self__) is type(request.instance) - ): - local_func = func.__func__.__get__(request.instance) - else: - local_func = func - - backend_name, backend_options = extract_backend_and_options(anyio_backend) - if has_backend_arg: - kwargs["anyio_backend"] = anyio_backend - - if has_request_arg: - kwargs["request"] = request - - with get_runner(backend_name, backend_options) as runner: - # re-entrant call into the test runner detected. this happens when an async fixture - # is dynamically requested via request.getfixturevalue() from inside a running async - # test or fixture. on asyncio this raises RuntimeError: This event loop is already - # running, on trio the runner deadlocks - the host loop blocks waiting for the - # coroutine to return, but the coroutine is waiting for the host loop. raising here - # prevents the hang and gives a consistent error across backends. - if runner.is_running(): - raise RuntimeError( - "Cannot schedule a coroutine in the test runner while another is already running; " - "likely caused by request.getfixturevalue() on an async fixture." - ) - - if isasyncgenfunction(local_func): - yield from runner.run_asyncgen_fixture(local_func, kwargs) - else: - yield runner.run_fixture(local_func, kwargs) - - # Only apply this to coroutine functions and async generator functions in requests - # that involve the anyio_backend fixture - func = fixturedef.func - if isasyncgenfunction(func) or iscoroutinefunction(func): - if "anyio_backend" in request.fixturenames: - fixturedef.func = wrapper - original_argname = fixturedef.argnames - - if not (has_backend_arg := "anyio_backend" in fixturedef.argnames): - fixturedef.argnames += ("anyio_backend",) - - if not (has_request_arg := "request" in fixturedef.argnames): - fixturedef.argnames += ("request",) - - try: - return (yield) - finally: - fixturedef.func = func - fixturedef.argnames = original_argname - - return (yield) - - -@pytest.hookimpl(tryfirst=True) -def pytest_pycollect_makeitem( - collector: pytest.Module | pytest.Class, name: str, obj: object -) -> None: - if collector.istestfunction(obj, name): - inner_func = obj.hypothesis.inner_test if hasattr(obj, "hypothesis") else obj - if iscoroutinefunction(inner_func): - anyio_auto_mode = collector.config.getini("anyio_mode") == "auto" - marker = collector.get_closest_marker("anyio") - own_markers = getattr(obj, "pytestmark", ()) - if ( - anyio_auto_mode - or marker - or any(marker.name == "anyio" for marker in own_markers) - ): - pytest.mark.usefixtures("anyio_backend")(obj) - - -def pytest_collection_finish(session: pytest.Session) -> None: - for i, item in reversed(list(enumerate(session.items))): - if ( - isinstance(item, pytest.Function) - and iscoroutinefunction(item.function) - and item.get_closest_marker("anyio") is not None - and "anyio_backend" not in item.fixturenames - ): - new_items = [] - try: - cs_fields = {f.name for f in dataclasses.fields(CallSpec2)} - except TypeError: - cs_fields = set() - - for param_index, backend in enumerate(get_available_backends()): - if "_arg2scope" in cs_fields: # pytest >= 8 - callspec = CallSpec2( - params={"anyio_backend": backend}, - indices={"anyio_backend": param_index}, - _arg2scope={"anyio_backend": Scope.Module}, - _idlist=[backend], - marks=[], - ) - else: # pytest 7.x - callspec = CallSpec2( # type: ignore[call-arg] - funcargs={}, - params={"anyio_backend": backend}, - indices={"anyio_backend": param_index}, - arg2scope={"anyio_backend": Scope.Module}, - idlist=[backend], - marks=[], - ) - - fi = item._fixtureinfo - new_names_closure = list(fi.names_closure) - if "anyio_backend" not in new_names_closure: - new_names_closure.append("anyio_backend") - - new_fixtureinfo = FuncFixtureInfo( - argnames=fi.argnames, - initialnames=fi.initialnames, - names_closure=new_names_closure, - name2fixturedefs=fi.name2fixturedefs, - ) - new_item = pytest.Function.from_parent( - item.parent, - name=f"{item.originalname}[{backend}]", - callspec=callspec, - callobj=item.obj, - fixtureinfo=new_fixtureinfo, - keywords=item.keywords, - originalname=item.originalname, - ) - new_items.append(new_item) - - session.items[i : i + 1] = new_items - - -@pytest.hookimpl(tryfirst=True) -def pytest_pyfunc_call(pyfuncitem: Any) -> bool | None: - def run_with_hypothesis(**kwargs: Any) -> None: - with get_runner(backend_name, backend_options) as runner: - runner.run_test(original_func, kwargs) - - backend = pyfuncitem.funcargs.get("anyio_backend") - if backend: - backend_name, backend_options = extract_backend_and_options(backend) - - if hasattr(pyfuncitem.obj, "hypothesis"): - # Wrap the inner test function unless it's already wrapped - original_func = pyfuncitem.obj.hypothesis.inner_test - if original_func.__qualname__ != run_with_hypothesis.__qualname__: - if iscoroutinefunction(original_func): - pyfuncitem.obj.hypothesis.inner_test = run_with_hypothesis - - return None - - if iscoroutinefunction(pyfuncitem.obj): - funcargs = pyfuncitem.funcargs - testargs = {arg: funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames} - with get_runner(backend_name, backend_options) as runner: - try: - runner.run_test(pyfuncitem.obj, testargs) - except ExceptionGroup as excgrp: - for exc in iterate_exceptions(excgrp): - if isinstance(exc, (Exit, KeyboardInterrupt, SystemExit)): - raise exc from excgrp - - raise - - return True - - return None - - -@pytest.fixture(scope="module", params=get_available_backends()) -def anyio_backend(request: Any) -> Any: - return request.param - - -@pytest.fixture -def anyio_backend_name(anyio_backend: Any) -> str: - if isinstance(anyio_backend, str): - return anyio_backend - else: - return anyio_backend[0] - - -@pytest.fixture -def anyio_backend_options(anyio_backend: Any) -> dict[str, Any]: - if isinstance(anyio_backend, str): - return {} - else: - return anyio_backend[1] - - -class FreePortFactory: - """ - Manages port generation based on specified socket kind, ensuring no duplicate - ports are generated. - - This class provides functionality for generating available free ports on the - system. It is initialized with a specific socket kind and can generate ports - for given address families while avoiding reuse of previously generated ports. - - Users should not instantiate this class directly, but use the - ``free_tcp_port_factory`` and ``free_udp_port_factory`` fixtures instead. For simple - uses cases, ``free_tcp_port`` and ``free_udp_port`` can be used instead. - """ - - def __init__(self, kind: socket.SocketKind) -> None: - self._kind = kind - self._generated = set[int]() - - @property - def kind(self) -> socket.SocketKind: - """ - The type of socket connection (e.g., :data:`~socket.SOCK_STREAM` or - :data:`~socket.SOCK_DGRAM`) used to bind for checking port availability - - """ - return self._kind - - def __call__(self, family: socket.AddressFamily | None = None) -> int: - """ - Return an unbound port for the given address family. - - :param family: if omitted, both IPv4 and IPv6 addresses will be tried - :return: a port number - - """ - if family is not None: - families = [family] - else: - families = [socket.AF_INET] - if socket.has_ipv6: - families.append(socket.AF_INET6) - - while True: - port = 0 - with ExitStack() as stack: - for family in families: - sock = stack.enter_context(socket.socket(family, self._kind)) - addr = "::1" if family == socket.AF_INET6 else "127.0.0.1" - try: - sock.bind((addr, port)) - except OSError: - break - - if not port: - port = sock.getsockname()[1] - else: - if port not in self._generated: - self._generated.add(port) - return port - - -@pytest.fixture(scope="session") -def free_tcp_port_factory() -> FreePortFactory: - return FreePortFactory(socket.SOCK_STREAM) - - -@pytest.fixture(scope="session") -def free_udp_port_factory() -> FreePortFactory: - return FreePortFactory(socket.SOCK_DGRAM) - - -@pytest.fixture -def free_tcp_port(free_tcp_port_factory: Callable[[], int]) -> int: - return free_tcp_port_factory() - - -@pytest.fixture -def free_udp_port(free_udp_port_factory: Callable[[], int]) -> int: - return free_udp_port_factory() diff --git a/server/venv/Lib/site-packages/anyio/streams/__init__.py b/server/venv/Lib/site-packages/anyio/streams/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/venv/Lib/site-packages/anyio/streams/buffered.py b/server/venv/Lib/site-packages/anyio/streams/buffered.py deleted file mode 100644 index acf312b..0000000 --- a/server/venv/Lib/site-packages/anyio/streams/buffered.py +++ /dev/null @@ -1,198 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "BufferedByteReceiveStream", - "BufferedByteStream", - "BufferedConnectable", -) - -import sys -from collections.abc import Callable, Iterable, Mapping -from dataclasses import dataclass, field -from typing import Any, SupportsIndex - -from .. import ClosedResourceError, DelimiterNotFound, EndOfStream, IncompleteRead -from ..abc import ( - AnyByteReceiveStream, - AnyByteStream, - AnyByteStreamConnectable, - ByteReceiveStream, - ByteStream, - ByteStreamConnectable, -) - -if sys.version_info >= (3, 12): - from typing import override -else: - from typing_extensions import override - - -@dataclass(eq=False) -class BufferedByteReceiveStream(ByteReceiveStream): - """ - Wraps any bytes-based receive stream and uses a buffer to provide sophisticated - receiving capabilities in the form of a byte stream. - """ - - receive_stream: AnyByteReceiveStream - _buffer: bytearray = field(init=False, default_factory=bytearray) - _closed: bool = field(init=False, default=False) - - async def aclose(self) -> None: - await self.receive_stream.aclose() - self._closed = True - - @property - def buffer(self) -> bytes: - """The bytes currently in the buffer.""" - return bytes(self._buffer) - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return self.receive_stream.extra_attributes - - def feed_data(self, data: Iterable[SupportsIndex], /) -> None: - """ - Append data directly into the buffer. - - Any data in the buffer will be consumed by receive operations before receiving - anything from the wrapped stream. - - :param data: the data to append to the buffer (can be bytes or anything else - that supports ``__index__()``) - - """ - self._buffer.extend(data) - - async def receive(self, max_bytes: int = 65536) -> bytes: - if self._closed: - raise ClosedResourceError - - if self._buffer: - chunk = bytes(self._buffer[:max_bytes]) - del self._buffer[:max_bytes] - return chunk - elif isinstance(self.receive_stream, ByteReceiveStream): - return await self.receive_stream.receive(max_bytes) - else: - # With a bytes-oriented object stream, we need to handle any surplus bytes - # we get from the receive() call - chunk = await self.receive_stream.receive() - if len(chunk) > max_bytes: - # Save the surplus bytes in the buffer - self._buffer.extend(chunk[max_bytes:]) - return chunk[:max_bytes] - else: - return chunk - - async def receive_exactly(self, nbytes: int) -> bytes: - """ - Read exactly the given amount of bytes from the stream. - - :param nbytes: the number of bytes to read - :return: the bytes read - :raises ~anyio.IncompleteRead: if the stream was closed before the requested - amount of bytes could be read from the stream - - """ - while True: - remaining = nbytes - len(self._buffer) - if remaining <= 0: - retval = self._buffer[:nbytes] - del self._buffer[:nbytes] - return bytes(retval) - - try: - if isinstance(self.receive_stream, ByteReceiveStream): - chunk = await self.receive_stream.receive(remaining) - else: - chunk = await self.receive_stream.receive() - except EndOfStream as exc: - raise IncompleteRead from exc - - self._buffer.extend(chunk) - - async def receive_until(self, delimiter: bytes, max_bytes: int) -> bytes: - """ - Read from the stream until the delimiter is found or max_bytes have been read. - - :param delimiter: the marker to look for in the stream - :param max_bytes: maximum number of bytes that will be read before raising - :exc:`~anyio.DelimiterNotFound` - :return: the bytes read (not including the delimiter) - :raises ~anyio.IncompleteRead: if the stream was closed before the delimiter - was found - :raises ~anyio.DelimiterNotFound: if the delimiter is not found within the - bytes read up to the maximum allowed - - """ - delimiter_size = len(delimiter) - offset = 0 - while True: - # Check if the delimiter can be found in the current buffer - index = self._buffer.find(delimiter, offset) - if index >= 0: - found = self._buffer[:index] - del self._buffer[: index + len(delimiter) :] - return bytes(found) - - # Check if the buffer is already at or over the limit - if len(self._buffer) >= max_bytes: - raise DelimiterNotFound(max_bytes) - - # Read more data into the buffer from the socket - try: - data = await self.receive_stream.receive() - except EndOfStream as exc: - raise IncompleteRead from exc - - # Move the offset forward and add the new data to the buffer - offset = max(len(self._buffer) - delimiter_size + 1, 0) - self._buffer.extend(data) - - -class BufferedByteStream(BufferedByteReceiveStream, ByteStream): - """ - A full-duplex variant of :class:`BufferedByteReceiveStream`. All writes are passed - through to the wrapped stream as-is. - """ - - def __init__(self, stream: AnyByteStream): - """ - :param stream: the stream to be wrapped - - """ - super().__init__(stream) - self._stream = stream - - @override - async def send_eof(self) -> None: - await self._stream.send_eof() - - @override - async def send(self, item: bytes) -> None: - await self._stream.send(item) - - -class BufferedConnectable(ByteStreamConnectable): - """ - Wraps a byte stream connectable to produce :class:`BufferedByteStream` connections. - - Use this when you want the streams returned by :meth:`connect` to have the buffered - receive API (e.g. :meth:`~BufferedByteReceiveStream.receive_exactly` and - :meth:`~BufferedByteReceiveStream.receive_until`). - - :param connectable: the byte stream connectable to wrap - """ - - def __init__(self, connectable: AnyByteStreamConnectable): - """ - :param connectable: the connectable to wrap - - """ - self.connectable = connectable - - @override - async def connect(self) -> BufferedByteStream: - stream = await self.connectable.connect() - return BufferedByteStream(stream) diff --git a/server/venv/Lib/site-packages/anyio/streams/file.py b/server/venv/Lib/site-packages/anyio/streams/file.py deleted file mode 100644 index 79c3d50..0000000 --- a/server/venv/Lib/site-packages/anyio/streams/file.py +++ /dev/null @@ -1,154 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "FileReadStream", - "FileStreamAttribute", - "FileWriteStream", -) - -from collections.abc import Callable, Mapping -from io import SEEK_SET, UnsupportedOperation -from os import PathLike -from pathlib import Path -from typing import IO, Any - -from .. import ( - BrokenResourceError, - ClosedResourceError, - EndOfStream, - TypedAttributeSet, - to_thread, - typed_attribute, -) -from ..abc import ByteReceiveStream, ByteSendStream - - -class FileStreamAttribute(TypedAttributeSet): - #: the open file descriptor - file: IO[bytes] = typed_attribute() - #: the path of the file on the file system, if available (file must be a real file) - path: Path = typed_attribute() - #: the file number, if available (file must be a real file or a TTY) - fileno: int = typed_attribute() - - -class _BaseFileStream: - def __init__(self, file: IO[bytes]): - self._file = file - - async def aclose(self) -> None: - await to_thread.run_sync(self._file.close) - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - attributes: dict[Any, Callable[[], Any]] = { - FileStreamAttribute.file: lambda: self._file, - } - - if hasattr(self._file, "name"): - attributes[FileStreamAttribute.path] = lambda: Path(self._file.name) - - try: - self._file.fileno() - except UnsupportedOperation: - pass - else: - attributes[FileStreamAttribute.fileno] = lambda: self._file.fileno() - - return attributes - - -class FileReadStream(_BaseFileStream, ByteReceiveStream): - """ - A byte stream that reads from a file in the file system. - - :param file: a file that has been opened for reading in binary mode - - .. versionadded:: 3.0 - """ - - @classmethod - async def from_path(cls, path: str | PathLike[str]) -> FileReadStream: - """ - Create a file read stream by opening the given file. - - :param path: path of the file to read from - - """ - file = await to_thread.run_sync(Path(path).open, "rb") - return cls(file) - - async def receive(self, max_bytes: int = 65536) -> bytes: - try: - data = await to_thread.run_sync(self._file.read, max_bytes) - except ValueError: - raise ClosedResourceError from None - except OSError as exc: - raise BrokenResourceError from exc - - if data: - return data - else: - raise EndOfStream - - async def seek(self, position: int, whence: int = SEEK_SET) -> int: - """ - Seek the file to the given position. - - .. seealso:: :meth:`io.IOBase.seek` - - .. note:: Not all file descriptors are seekable. - - :param position: position to seek the file to - :param whence: controls how ``position`` is interpreted - :return: the new absolute position - :raises OSError: if the file is not seekable - - """ - return await to_thread.run_sync(self._file.seek, position, whence) - - async def tell(self) -> int: - """ - Return the current stream position. - - .. note:: Not all file descriptors are seekable. - - :return: the current absolute position - :raises OSError: if the file is not seekable - - """ - return await to_thread.run_sync(self._file.tell) - - -class FileWriteStream(_BaseFileStream, ByteSendStream): - """ - A byte stream that writes to a file in the file system. - - :param file: a file that has been opened for writing in binary mode - - .. versionadded:: 3.0 - """ - - @classmethod - async def from_path( - cls, path: str | PathLike[str], append: bool = False - ) -> FileWriteStream: - """ - Create a file write stream by opening the given file for writing. - - :param path: path of the file to write to - :param append: if ``True``, open the file for appending; if ``False``, any - existing file at the given path will be truncated - - """ - mode = "ab" if append else "wb" - file = await to_thread.run_sync(Path(path).open, mode) - return cls(file) - - async def send(self, item: bytes) -> None: - try: - await to_thread.run_sync(self._file.write, item) - except ValueError: - raise ClosedResourceError from None - except OSError as exc: - raise BrokenResourceError from exc diff --git a/server/venv/Lib/site-packages/anyio/streams/memory.py b/server/venv/Lib/site-packages/anyio/streams/memory.py deleted file mode 100644 index a3fa0c3..0000000 --- a/server/venv/Lib/site-packages/anyio/streams/memory.py +++ /dev/null @@ -1,325 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "MemoryObjectReceiveStream", - "MemoryObjectSendStream", - "MemoryObjectStreamStatistics", -) - -import warnings -from collections import OrderedDict, deque -from dataclasses import dataclass, field -from types import TracebackType -from typing import Generic, NamedTuple, TypeVar - -from .. import ( - BrokenResourceError, - ClosedResourceError, - EndOfStream, - WouldBlock, -) -from .._core._testing import TaskInfo, get_current_task -from ..abc import Event, ObjectReceiveStream, ObjectSendStream -from ..lowlevel import checkpoint - -T_Item = TypeVar("T_Item") -T_co = TypeVar("T_co", covariant=True) -T_contra = TypeVar("T_contra", contravariant=True) - - -class MemoryObjectStreamStatistics(NamedTuple): - current_buffer_used: int #: number of items stored in the buffer - #: maximum number of items that can be stored on this stream (or :data:`math.inf`) - max_buffer_size: float - open_send_streams: int #: number of unclosed clones of the send stream - open_receive_streams: int #: number of unclosed clones of the receive stream - #: number of tasks blocked on :meth:`MemoryObjectSendStream.send` - tasks_waiting_send: int - #: number of tasks blocked on :meth:`MemoryObjectReceiveStream.receive` - tasks_waiting_receive: int - - -@dataclass(eq=False) -class _MemoryObjectItemReceiver(Generic[T_Item]): - task_info: TaskInfo = field(init=False, default_factory=get_current_task) - item: T_Item = field(init=False) - - def __repr__(self) -> str: - # When item is not defined, we get following error with default __repr__: - # AttributeError: 'MemoryObjectItemReceiver' object has no attribute 'item' - item = getattr(self, "item", None) - return f"{self.__class__.__name__}(task_info={self.task_info}, item={item!r})" - - -@dataclass(eq=False) -class _MemoryObjectStreamState(Generic[T_Item]): - max_buffer_size: float = field() - buffer: deque[T_Item] = field(init=False, default_factory=deque) - open_send_channels: int = field(init=False, default=0) - open_receive_channels: int = field(init=False, default=0) - waiting_receivers: OrderedDict[Event, _MemoryObjectItemReceiver[T_Item]] = field( - init=False, default_factory=OrderedDict - ) - waiting_senders: OrderedDict[Event, T_Item] = field( - init=False, default_factory=OrderedDict - ) - - def statistics(self) -> MemoryObjectStreamStatistics: - return MemoryObjectStreamStatistics( - len(self.buffer), - self.max_buffer_size, - self.open_send_channels, - self.open_receive_channels, - len(self.waiting_senders), - len(self.waiting_receivers), - ) - - -@dataclass(eq=False) -class MemoryObjectReceiveStream(Generic[T_co], ObjectReceiveStream[T_co]): - _state: _MemoryObjectStreamState[T_co] - _closed: bool = field(init=False, default=False) - - def __post_init__(self) -> None: - self._state.open_receive_channels += 1 - - def receive_nowait(self) -> T_co: - """ - Receive the next item if it can be done without waiting. - - :return: the received item - :raises ~anyio.ClosedResourceError: if this send stream has been closed - :raises ~anyio.EndOfStream: if the buffer is empty and this stream has been - closed from the sending end - :raises ~anyio.WouldBlock: if there are no items in the buffer and no tasks - waiting to send - - """ - if self._closed: - raise ClosedResourceError - - if self._state.waiting_senders: - # Get the item from the next sender - send_event, item = self._state.waiting_senders.popitem(last=False) - self._state.buffer.append(item) - send_event.set() - - if self._state.buffer: - return self._state.buffer.popleft() - elif not self._state.open_send_channels: - raise EndOfStream - - raise WouldBlock - - async def receive(self) -> T_co: - await checkpoint() - try: - return self.receive_nowait() - except WouldBlock: - # Add ourselves in the queue - receive_event = Event() - receiver = _MemoryObjectItemReceiver[T_co]() - self._state.waiting_receivers[receive_event] = receiver - - try: - await receive_event.wait() - finally: - self._state.waiting_receivers.pop(receive_event, None) - - try: - return receiver.item - except AttributeError: - raise EndOfStream from None - - def clone(self) -> MemoryObjectReceiveStream[T_co]: - """ - Create a clone of this receive stream. - - Each clone can be closed separately. Only when all clones have been closed will - the receiving end of the memory stream be considered closed by the sending ends. - - :return: the cloned stream - - """ - if self._closed: - raise ClosedResourceError - - return MemoryObjectReceiveStream(_state=self._state) - - def close(self) -> None: - """ - Close the stream. - - This works the exact same way as :meth:`aclose`, but is provided as a special - case for the benefit of synchronous callbacks. - - """ - if not self._closed: - self._closed = True - self._state.open_receive_channels -= 1 - if self._state.open_receive_channels == 0: - send_events = list(self._state.waiting_senders.keys()) - for event in send_events: - event.set() - - async def aclose(self) -> None: - self.close() - - def statistics(self) -> MemoryObjectStreamStatistics: - """ - Return statistics about the current state of this stream. - - .. versionadded:: 3.0 - """ - return self._state.statistics() - - def __enter__(self) -> MemoryObjectReceiveStream[T_co]: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.close() - - def __del__(self) -> None: - if not self._closed: - warnings.warn( - f"Unclosed <{self.__class__.__name__} at {id(self):x}>", - ResourceWarning, - stacklevel=1, - source=self, - ) - - -@dataclass(eq=False) -class MemoryObjectSendStream(Generic[T_contra], ObjectSendStream[T_contra]): - _state: _MemoryObjectStreamState[T_contra] - _closed: bool = field(init=False, default=False) - - def __post_init__(self) -> None: - self._state.open_send_channels += 1 - - def send_nowait(self, item: T_contra) -> None: - """ - Send an item immediately if it can be done without waiting. - - :param item: the item to send - :raises ~anyio.ClosedResourceError: if this send stream has been closed - :raises ~anyio.BrokenResourceError: if the stream has been closed from the - receiving end - :raises ~anyio.WouldBlock: if the buffer is full and there are no tasks waiting - to receive - - """ - if self._closed: - raise ClosedResourceError - if not self._state.open_receive_channels: - raise BrokenResourceError - - while self._state.waiting_receivers: - receive_event, receiver = self._state.waiting_receivers.popitem(last=False) - if not receiver.task_info.has_pending_cancellation(): - receiver.item = item - receive_event.set() - return - - if len(self._state.buffer) < self._state.max_buffer_size: - self._state.buffer.append(item) - else: - raise WouldBlock - - async def send(self, item: T_contra) -> None: - """ - Send an item to the stream. - - If the buffer is full, this method blocks until there is again room in the - buffer or the item can be sent directly to a receiver. - - :param item: the item to send - :raises ~anyio.ClosedResourceError: if this send stream has been closed - :raises ~anyio.BrokenResourceError: if the stream has been closed from the - receiving end - - """ - await checkpoint() - try: - self.send_nowait(item) - except WouldBlock: - # Wait until there's someone on the receiving end - send_event = Event() - self._state.waiting_senders[send_event] = item - try: - await send_event.wait() - except BaseException: - self._state.waiting_senders.pop(send_event, None) - raise - - if send_event in self._state.waiting_senders: - del self._state.waiting_senders[send_event] - raise BrokenResourceError from None - - def clone(self) -> MemoryObjectSendStream[T_contra]: - """ - Create a clone of this send stream. - - Each clone can be closed separately. Only when all clones have been closed will - the sending end of the memory stream be considered closed by the receiving ends. - - :return: the cloned stream - - """ - if self._closed: - raise ClosedResourceError - - return MemoryObjectSendStream(_state=self._state) - - def close(self) -> None: - """ - Close the stream. - - This works the exact same way as :meth:`aclose`, but is provided as a special - case for the benefit of synchronous callbacks. - - """ - if not self._closed: - self._closed = True - self._state.open_send_channels -= 1 - if self._state.open_send_channels == 0: - receive_events = list(self._state.waiting_receivers.keys()) - self._state.waiting_receivers.clear() - for event in receive_events: - event.set() - - async def aclose(self) -> None: - self.close() - - def statistics(self) -> MemoryObjectStreamStatistics: - """ - Return statistics about the current state of this stream. - - .. versionadded:: 3.0 - """ - return self._state.statistics() - - def __enter__(self) -> MemoryObjectSendStream[T_contra]: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.close() - - def __del__(self) -> None: - if not self._closed: - warnings.warn( - f"Unclosed <{self.__class__.__name__} at {id(self):x}>", - ResourceWarning, - stacklevel=1, - source=self, - ) diff --git a/server/venv/Lib/site-packages/anyio/streams/stapled.py b/server/venv/Lib/site-packages/anyio/streams/stapled.py deleted file mode 100644 index 9248b68..0000000 --- a/server/venv/Lib/site-packages/anyio/streams/stapled.py +++ /dev/null @@ -1,147 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "MultiListener", - "StapledByteStream", - "StapledObjectStream", -) - -from collections.abc import Callable, Mapping, Sequence -from dataclasses import dataclass -from typing import Any, Generic, TypeVar - -from ..abc import ( - ByteReceiveStream, - ByteSendStream, - ByteStream, - Listener, - ObjectReceiveStream, - ObjectSendStream, - ObjectStream, - TaskGroup, -) - -T_Item = TypeVar("T_Item") -T_Stream = TypeVar("T_Stream") - - -@dataclass(eq=False) -class StapledByteStream(ByteStream): - """ - Combines two byte streams into a single, bidirectional byte stream. - - Extra attributes will be provided from both streams, with the receive stream - providing the values in case of a conflict. - - :param ByteSendStream send_stream: the sending byte stream - :param ByteReceiveStream receive_stream: the receiving byte stream - """ - - send_stream: ByteSendStream - receive_stream: ByteReceiveStream - - async def receive(self, max_bytes: int = 65536) -> bytes: - return await self.receive_stream.receive(max_bytes) - - async def send(self, item: bytes) -> None: - await self.send_stream.send(item) - - async def send_eof(self) -> None: - await self.send_stream.aclose() - - async def aclose(self) -> None: - await self.send_stream.aclose() - await self.receive_stream.aclose() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return { - **self.send_stream.extra_attributes, - **self.receive_stream.extra_attributes, - } - - -@dataclass(eq=False) -class StapledObjectStream(Generic[T_Item], ObjectStream[T_Item]): - """ - Combines two object streams into a single, bidirectional object stream. - - Extra attributes will be provided from both streams, with the receive stream - providing the values in case of a conflict. - - :param ObjectSendStream send_stream: the sending object stream - :param ObjectReceiveStream receive_stream: the receiving object stream - """ - - send_stream: ObjectSendStream[T_Item] - receive_stream: ObjectReceiveStream[T_Item] - - async def receive(self) -> T_Item: - return await self.receive_stream.receive() - - async def send(self, item: T_Item) -> None: - await self.send_stream.send(item) - - async def send_eof(self) -> None: - await self.send_stream.aclose() - - async def aclose(self) -> None: - await self.send_stream.aclose() - await self.receive_stream.aclose() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return { - **self.send_stream.extra_attributes, - **self.receive_stream.extra_attributes, - } - - -@dataclass(eq=False) -class MultiListener(Generic[T_Stream], Listener[T_Stream]): - """ - Combines multiple listeners into one, serving connections from all of them at once. - - Any MultiListeners in the given collection of listeners will have their listeners - moved into this one. - - Extra attributes are provided from each listener, with each successive listener - overriding any conflicting attributes from the previous one. - - :param listeners: listeners to serve - :type listeners: Sequence[Listener[T_Stream]] - """ - - listeners: Sequence[Listener[T_Stream]] - - def __post_init__(self) -> None: - listeners: list[Listener[T_Stream]] = [] - for listener in self.listeners: - if isinstance(listener, MultiListener): - listeners.extend(listener.listeners) - del listener.listeners[:] # type: ignore[attr-defined] - else: - listeners.append(listener) - - self.listeners = listeners - - async def serve( - self, handler: Callable[[T_Stream], Any], task_group: TaskGroup | None = None - ) -> None: - from .. import create_task_group - - async with create_task_group() as tg: - for listener in self.listeners: - tg.start_soon(listener.serve, handler, task_group) - - async def aclose(self) -> None: - for listener in self.listeners: - await listener.aclose() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - attributes: dict = {} - for listener in self.listeners: - attributes.update(listener.extra_attributes) - - return attributes diff --git a/server/venv/Lib/site-packages/anyio/streams/text.py b/server/venv/Lib/site-packages/anyio/streams/text.py deleted file mode 100644 index 296cd25..0000000 --- a/server/venv/Lib/site-packages/anyio/streams/text.py +++ /dev/null @@ -1,176 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "TextConnectable", - "TextReceiveStream", - "TextSendStream", - "TextStream", -) - -import codecs -import sys -from collections.abc import Callable, Mapping -from dataclasses import InitVar, dataclass, field -from typing import Any - -from ..abc import ( - AnyByteReceiveStream, - AnyByteSendStream, - AnyByteStream, - AnyByteStreamConnectable, - ObjectReceiveStream, - ObjectSendStream, - ObjectStream, - ObjectStreamConnectable, -) - -if sys.version_info >= (3, 12): - from typing import override -else: - from typing_extensions import override - - -@dataclass(eq=False) -class TextReceiveStream(ObjectReceiveStream[str]): - """ - Stream wrapper that decodes bytes to strings using the given encoding. - - Decoding is done using :class:`~codecs.IncrementalDecoder` which returns any - completely received unicode characters as soon as they come in. - - :param transport_stream: any bytes-based receive stream - :param encoding: character encoding to use for decoding bytes to strings (defaults - to ``utf-8``) - :param errors: handling scheme for decoding errors (defaults to ``strict``; see the - `codecs module documentation`_ for a comprehensive list of options) - - .. _codecs module documentation: - https://docs.python.org/3/library/codecs.html#codec-objects - """ - - transport_stream: AnyByteReceiveStream - encoding: InitVar[str] = "utf-8" - errors: InitVar[str] = "strict" - _decoder: codecs.IncrementalDecoder = field(init=False) - - def __post_init__(self, encoding: str, errors: str) -> None: - decoder_class = codecs.getincrementaldecoder(encoding) - self._decoder = decoder_class(errors=errors) - - async def receive(self) -> str: - while True: - chunk = await self.transport_stream.receive() - decoded = self._decoder.decode(chunk) - if decoded: - return decoded - - async def aclose(self) -> None: - await self.transport_stream.aclose() - self._decoder.reset() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return self.transport_stream.extra_attributes - - -@dataclass(eq=False) -class TextSendStream(ObjectSendStream[str]): - """ - Sends strings to the wrapped stream as bytes using the given encoding. - - :param AnyByteSendStream transport_stream: any bytes-based send stream - :param str encoding: character encoding to use for encoding strings to bytes - (defaults to ``utf-8``) - :param str errors: handling scheme for encoding errors (defaults to ``strict``; see - the `codecs module documentation`_ for a comprehensive list of options) - - .. _codecs module documentation: - https://docs.python.org/3/library/codecs.html#codec-objects - """ - - transport_stream: AnyByteSendStream - encoding: InitVar[str] = "utf-8" - errors: str = "strict" - _encoder: Callable[..., tuple[bytes, int]] = field(init=False) - - def __post_init__(self, encoding: str) -> None: - self._encoder = codecs.getencoder(encoding) - - async def send(self, item: str) -> None: - encoded = self._encoder(item, self.errors)[0] - await self.transport_stream.send(encoded) - - async def aclose(self) -> None: - await self.transport_stream.aclose() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return self.transport_stream.extra_attributes - - -@dataclass(eq=False) -class TextStream(ObjectStream[str]): - """ - A bidirectional stream that decodes bytes to strings on receive and encodes strings - to bytes on send. - - Extra attributes will be provided from both streams, with the receive stream - providing the values in case of a conflict. - - :param AnyByteStream transport_stream: any bytes-based stream - :param str encoding: character encoding to use for encoding/decoding strings to/from - bytes (defaults to ``utf-8``) - :param str errors: handling scheme for encoding errors (defaults to ``strict``; see - the `codecs module documentation`_ for a comprehensive list of options) - - .. _codecs module documentation: - https://docs.python.org/3/library/codecs.html#codec-objects - """ - - transport_stream: AnyByteStream - encoding: InitVar[str] = "utf-8" - errors: InitVar[str] = "strict" - _receive_stream: TextReceiveStream = field(init=False) - _send_stream: TextSendStream = field(init=False) - - def __post_init__(self, encoding: str, errors: str) -> None: - self._receive_stream = TextReceiveStream( - self.transport_stream, encoding=encoding, errors=errors - ) - self._send_stream = TextSendStream( - self.transport_stream, encoding=encoding, errors=errors - ) - - async def receive(self) -> str: - return await self._receive_stream.receive() - - async def send(self, item: str) -> None: - await self._send_stream.send(item) - - async def send_eof(self) -> None: - await self.transport_stream.send_eof() - - async def aclose(self) -> None: - await self._send_stream.aclose() - await self._receive_stream.aclose() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return { - **self._send_stream.extra_attributes, - **self._receive_stream.extra_attributes, - } - - -class TextConnectable(ObjectStreamConnectable[str]): - def __init__(self, connectable: AnyByteStreamConnectable): - """ - :param connectable: the bytestream endpoint to wrap - - """ - self.connectable = connectable - - @override - async def connect(self) -> TextStream: - stream = await self.connectable.connect() - return TextStream(stream) diff --git a/server/venv/Lib/site-packages/anyio/streams/tls.py b/server/venv/Lib/site-packages/anyio/streams/tls.py deleted file mode 100644 index e2a7ca5..0000000 --- a/server/venv/Lib/site-packages/anyio/streams/tls.py +++ /dev/null @@ -1,421 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "TLSAttribute", - "TLSConnectable", - "TLSListener", - "TLSStream", -) - -import logging -import re -import ssl -import sys -from collections.abc import Callable, Mapping -from dataclasses import dataclass -from functools import wraps -from ssl import SSLContext -from typing import Any, TypeAlias, TypeVar - -from .. import ( - BrokenResourceError, - EndOfStream, - aclose_forcefully, - get_cancelled_exc_class, - to_thread, -) -from .._core._typedattr import TypedAttributeSet, typed_attribute -from ..abc import ( - AnyByteStream, - AnyByteStreamConnectable, - ByteStream, - ByteStreamConnectable, - Listener, - TaskGroup, -) - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -if sys.version_info >= (3, 12): - from typing import override -else: - from typing_extensions import override - -T_Retval = TypeVar("T_Retval") -PosArgsT = TypeVarTuple("PosArgsT") -_PCTRTT: TypeAlias = tuple[tuple[str, str], ...] -_PCTRTTT: TypeAlias = tuple[_PCTRTT, ...] - - -class TLSAttribute(TypedAttributeSet): - """Contains Transport Layer Security related attributes.""" - - #: the selected ALPN protocol - alpn_protocol: str | None = typed_attribute() - #: the channel binding for type ``tls-unique`` - channel_binding_tls_unique: bytes = typed_attribute() - #: the selected cipher - cipher: tuple[str, str, int] = typed_attribute() - #: the peer certificate in dictionary form (see :meth:`ssl.SSLSocket.getpeercert` - # for more information) - peer_certificate: None | (dict[str, str | _PCTRTTT | _PCTRTT]) = typed_attribute() - #: the peer certificate in binary form - peer_certificate_binary: bytes | None = typed_attribute() - #: ``True`` if this is the server side of the connection - server_side: bool = typed_attribute() - #: ciphers shared by the client during the TLS handshake (``None`` if this is the - #: client side) - shared_ciphers: list[tuple[str, str, int]] | None = typed_attribute() - #: the :class:`~ssl.SSLObject` used for encryption - ssl_object: ssl.SSLObject = typed_attribute() - #: ``True`` if this stream does (and expects) a closing TLS handshake when the - #: stream is being closed - standard_compatible: bool = typed_attribute() - #: the TLS protocol version (e.g. ``TLSv1.2``) - tls_version: str = typed_attribute() - - -@dataclass(eq=False) -class TLSStream(ByteStream): - """ - A stream wrapper that encrypts all sent data and decrypts received data. - - This class has no public initializer; use :meth:`wrap` instead. - All extra attributes from :class:`~TLSAttribute` are supported. - - :var AnyByteStream transport_stream: the wrapped stream - - """ - - transport_stream: AnyByteStream - standard_compatible: bool - _ssl_object: ssl.SSLObject - _read_bio: ssl.MemoryBIO - _write_bio: ssl.MemoryBIO - - @classmethod - async def wrap( - cls, - transport_stream: AnyByteStream, - *, - server_side: bool | None = None, - hostname: str | None = None, - ssl_context: ssl.SSLContext | None = None, - standard_compatible: bool = True, - ) -> TLSStream: - """ - Wrap an existing stream with Transport Layer Security. - - This performs a TLS handshake with the peer. - - :param transport_stream: a bytes-transporting stream to wrap - :param server_side: ``True`` if this is the server side of the connection, - ``False`` if this is the client side (if omitted, will be set to ``False`` - if ``hostname`` has been provided, ``False`` otherwise). Used only to create - a default context when an explicit context has not been provided. - :param hostname: host name of the peer (if host name checking is desired) - :param ssl_context: the SSLContext object to use (if not provided, a secure - default will be created) - :param standard_compatible: if ``False``, skip the closing handshake when - closing the connection, and don't raise an exception if the peer does the - same - :raises ~ssl.SSLError: if the TLS handshake fails - - """ - if server_side is None: - server_side = not hostname - - if not ssl_context: - purpose = ( - ssl.Purpose.CLIENT_AUTH if server_side else ssl.Purpose.SERVER_AUTH - ) - ssl_context = ssl.create_default_context(purpose) - - # Re-enable detection of unexpected EOFs if it was disabled by Python - if hasattr(ssl, "OP_IGNORE_UNEXPECTED_EOF"): - ssl_context.options &= ~ssl.OP_IGNORE_UNEXPECTED_EOF - - bio_in = ssl.MemoryBIO() - bio_out = ssl.MemoryBIO() - - # External SSLContext implementations may do blocking I/O in wrap_bio(), - # but the standard library implementation won't - if type(ssl_context) is ssl.SSLContext: - ssl_object = ssl_context.wrap_bio( - bio_in, bio_out, server_side=server_side, server_hostname=hostname - ) - else: - ssl_object = await to_thread.run_sync( - ssl_context.wrap_bio, - bio_in, - bio_out, - server_side, - hostname, - None, - ) - - wrapper = cls( - transport_stream=transport_stream, - standard_compatible=standard_compatible, - _ssl_object=ssl_object, - _read_bio=bio_in, - _write_bio=bio_out, - ) - await wrapper._call_sslobject_method(ssl_object.do_handshake) - return wrapper - - async def _call_sslobject_method( - self, func: Callable[[Unpack[PosArgsT]], T_Retval], *args: Unpack[PosArgsT] - ) -> T_Retval: - while True: - try: - result = func(*args) - except ssl.SSLWantReadError: - try: - # Flush any pending writes first - if self._write_bio.pending: - await self.transport_stream.send(self._write_bio.read()) - - data = await self.transport_stream.receive() - except EndOfStream: - self._read_bio.write_eof() - except OSError as exc: - self._read_bio.write_eof() - self._write_bio.write_eof() - raise BrokenResourceError from exc - else: - self._read_bio.write(data) - except ssl.SSLWantWriteError: - await self.transport_stream.send(self._write_bio.read()) - except ssl.SSLSyscallError as exc: - self._read_bio.write_eof() - self._write_bio.write_eof() - raise BrokenResourceError from exc - except ssl.SSLError as exc: - self._read_bio.write_eof() - self._write_bio.write_eof() - if isinstance(exc, ssl.SSLEOFError) or ( - exc.strerror and "UNEXPECTED_EOF_WHILE_READING" in exc.strerror - ): - if self.standard_compatible: - raise BrokenResourceError from exc - else: - raise EndOfStream from None - - raise - else: - # Flush any pending writes first - if self._write_bio.pending: - await self.transport_stream.send(self._write_bio.read()) - - return result - - async def unwrap(self) -> tuple[AnyByteStream, bytes]: - """ - Does the TLS closing handshake. - - :return: a tuple of (wrapped byte stream, bytes left in the read buffer) - - """ - await self._call_sslobject_method(self._ssl_object.unwrap) - self._read_bio.write_eof() - self._write_bio.write_eof() - return self.transport_stream, self._read_bio.read() - - async def aclose(self) -> None: - if self.standard_compatible: - try: - await self.unwrap() - except BaseException: - await aclose_forcefully(self.transport_stream) - raise - - await self.transport_stream.aclose() - - async def receive(self, max_bytes: int = 65536) -> bytes: - data = await self._call_sslobject_method(self._ssl_object.read, max_bytes) - if not data: - raise EndOfStream - - return data - - async def send(self, item: bytes) -> None: - await self._call_sslobject_method(self._ssl_object.write, item) - - async def send_eof(self) -> None: - tls_version = self.extra(TLSAttribute.tls_version) - match = re.match(r"TLSv(\d+)(?:\.(\d+))?", tls_version) - if match: - major, minor = int(match.group(1)), int(match.group(2) or 0) - if (major, minor) < (1, 3): - raise NotImplementedError( - f"send_eof() requires at least TLSv1.3; current " - f"session uses {tls_version}" - ) - - raise NotImplementedError( - "send_eof() has not yet been implemented for TLS streams" - ) - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return { - **self.transport_stream.extra_attributes, - TLSAttribute.alpn_protocol: self._ssl_object.selected_alpn_protocol, - TLSAttribute.channel_binding_tls_unique: ( - self._ssl_object.get_channel_binding - ), - TLSAttribute.cipher: self._ssl_object.cipher, - TLSAttribute.peer_certificate: lambda: self._ssl_object.getpeercert(False), - TLSAttribute.peer_certificate_binary: lambda: self._ssl_object.getpeercert( - True - ), - TLSAttribute.server_side: lambda: self._ssl_object.server_side, - TLSAttribute.shared_ciphers: lambda: ( - self._ssl_object.shared_ciphers() - if self._ssl_object.server_side - else None - ), - TLSAttribute.standard_compatible: lambda: self.standard_compatible, - TLSAttribute.ssl_object: lambda: self._ssl_object, - TLSAttribute.tls_version: self._ssl_object.version, - } - - -@dataclass(eq=False) -class TLSListener(Listener[TLSStream]): - """ - A convenience listener that wraps another listener and auto-negotiates a TLS session - on every accepted connection. - - If the TLS handshake times out or raises an exception, - :meth:`handle_handshake_error` is called to do whatever post-mortem processing is - deemed necessary. - - Supports only the :attr:`~TLSAttribute.standard_compatible` extra attribute. - - :param Listener listener: the listener to wrap - :param ssl_context: the SSL context object - :param standard_compatible: a flag passed through to :meth:`TLSStream.wrap` - :param handshake_timeout: time limit for the TLS handshake - (passed to :func:`~anyio.fail_after`) - """ - - listener: Listener[Any] - ssl_context: ssl.SSLContext - standard_compatible: bool = True - handshake_timeout: float = 30 - - @staticmethod - async def handle_handshake_error(exc: BaseException, stream: AnyByteStream) -> None: - """ - Handle an exception raised during the TLS handshake. - - This method does 3 things: - - #. Forcefully closes the original stream - #. Logs the exception (unless it was a cancellation exception) using the - ``anyio.streams.tls`` logger - #. Reraises the exception if it was a base exception or a cancellation exception - - :param exc: the exception - :param stream: the original stream - - """ - await aclose_forcefully(stream) - - # Log all except cancellation exceptions - if not isinstance(exc, get_cancelled_exc_class()): - # CPython (as of 3.11.5) returns incorrect `sys.exc_info()` here when using - # any asyncio implementation, so we explicitly pass the exception to log - # (https://github.com/python/cpython/issues/108668). Trio does not have this - # issue because it works around the CPython bug. - logging.getLogger(__name__).exception( - "Error during TLS handshake", exc_info=exc - ) - - # Only reraise base exceptions and cancellation exceptions - if not isinstance(exc, Exception) or isinstance(exc, get_cancelled_exc_class()): - raise - - async def serve( - self, - handler: Callable[[TLSStream], Any], - task_group: TaskGroup | None = None, - ) -> None: - @wraps(handler) - async def handler_wrapper(stream: AnyByteStream) -> None: - from .. import fail_after - - try: - with fail_after(self.handshake_timeout): - wrapped_stream = await TLSStream.wrap( - stream, - ssl_context=self.ssl_context, - standard_compatible=self.standard_compatible, - ) - except BaseException as exc: - await self.handle_handshake_error(exc, stream) - else: - await handler(wrapped_stream) - - await self.listener.serve(handler_wrapper, task_group) - - async def aclose(self) -> None: - await self.listener.aclose() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return { - TLSAttribute.standard_compatible: lambda: self.standard_compatible, - } - - -class TLSConnectable(ByteStreamConnectable): - """ - Wraps another connectable and does TLS negotiation after a successful connection. - - :param connectable: the connectable to wrap - :param hostname: host name of the server (if host name checking is desired) - :param ssl_context: the SSLContext object to use (if not provided, a secure default - will be created) - :param standard_compatible: if ``False``, skip the closing handshake when closing - the connection, and don't raise an exception if the server does the same - """ - - def __init__( - self, - connectable: AnyByteStreamConnectable, - *, - hostname: str | None = None, - ssl_context: ssl.SSLContext | None = None, - standard_compatible: bool = True, - ) -> None: - self.connectable = connectable - self.ssl_context: SSLContext = ssl_context or ssl.create_default_context( - ssl.Purpose.SERVER_AUTH - ) - if not isinstance(self.ssl_context, ssl.SSLContext): - raise TypeError( - "ssl_context must be an instance of ssl.SSLContext, not " - f"{type(self.ssl_context).__name__}" - ) - self.hostname = hostname - self.standard_compatible = standard_compatible - - @override - async def connect(self) -> TLSStream: - stream = await self.connectable.connect() - try: - return await TLSStream.wrap( - stream, - hostname=self.hostname, - ssl_context=self.ssl_context, - standard_compatible=self.standard_compatible, - ) - except BaseException: - await aclose_forcefully(stream) - raise diff --git a/server/venv/Lib/site-packages/anyio/to_interpreter.py b/server/venv/Lib/site-packages/anyio/to_interpreter.py deleted file mode 100644 index 694dbe7..0000000 --- a/server/venv/Lib/site-packages/anyio/to_interpreter.py +++ /dev/null @@ -1,246 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "run_sync", - "current_default_interpreter_limiter", -) - -import atexit -import os -import sys -from collections import deque -from collections.abc import Callable -from typing import Any, Final, TypeVar - -from . import current_time, to_thread -from ._core._exceptions import BrokenWorkerInterpreter -from ._core._synchronization import CapacityLimiter -from .lowlevel import RunVar - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -if sys.version_info >= (3, 14): - from concurrent.interpreters import ExecutionFailed, create - - def _interp_call( - func: Callable[..., Any], args: tuple[Any, ...] - ) -> tuple[Any, bool]: - try: - retval = func(*args) - except BaseException as exc: - return exc, True - else: - return retval, False - - class _Worker: - last_used: float = 0 - - def __init__(self) -> None: - self._interpreter = create() - - def destroy(self) -> None: - self._interpreter.close() - - def call( - self, - func: Callable[..., T_Retval], - args: tuple[Any, ...], - ) -> T_Retval: - try: - res, is_exception = self._interpreter.call(_interp_call, func, args) - except ExecutionFailed as exc: - raise BrokenWorkerInterpreter(exc.excinfo) from exc - - if is_exception: - raise res - - return res -elif sys.version_info >= (3, 13): - import _interpqueues - import _interpreters - - UNBOUND: Final = 2 # I have no clue how this works, but it was used in the stdlib - FMT_UNPICKLED: Final = 0 - FMT_PICKLED: Final = 1 - QUEUE_PICKLE_ARGS: Final = (FMT_PICKLED, UNBOUND) - QUEUE_UNPICKLE_ARGS: Final = (FMT_UNPICKLED, UNBOUND) - - _run_func = compile( - """ -import _interpqueues -from _interpreters import NotShareableError -from pickle import loads, dumps, HIGHEST_PROTOCOL - -QUEUE_PICKLE_ARGS = (1, 2) -QUEUE_UNPICKLE_ARGS = (0, 2) - -item = _interpqueues.get(queue_id)[0] -try: - func, args = loads(item) - retval = func(*args) -except BaseException as exc: - is_exception = True - retval = exc -else: - is_exception = False - -try: - _interpqueues.put(queue_id, (retval, is_exception), *QUEUE_UNPICKLE_ARGS) -except NotShareableError: - retval = dumps(retval, HIGHEST_PROTOCOL) - _interpqueues.put(queue_id, (retval, is_exception), *QUEUE_PICKLE_ARGS) - """, - "", - "exec", - ) - - class _Worker: - last_used: float = 0 - - def __init__(self) -> None: - self._interpreter_id = _interpreters.create() - self._queue_id = _interpqueues.create(1, *QUEUE_UNPICKLE_ARGS) - _interpreters.set___main___attrs( - self._interpreter_id, {"queue_id": self._queue_id} - ) - - def destroy(self) -> None: - _interpqueues.destroy(self._queue_id) - _interpreters.destroy(self._interpreter_id) - - def call( - self, - func: Callable[..., T_Retval], - args: tuple[Any, ...], - ) -> T_Retval: - import pickle - - item = pickle.dumps((func, args), pickle.HIGHEST_PROTOCOL) - _interpqueues.put(self._queue_id, item, *QUEUE_PICKLE_ARGS) - exc_info = _interpreters.exec(self._interpreter_id, _run_func) - if exc_info: - raise BrokenWorkerInterpreter(exc_info) - - res = _interpqueues.get(self._queue_id) - (res, is_exception), fmt = res[:2] - if fmt == FMT_PICKLED: - res = pickle.loads(res) - - if is_exception: - raise res - - return res -else: - - class _Worker: - last_used: float = 0 - - def __init__(self) -> None: - raise RuntimeError("subinterpreters require at least Python 3.13") - - def call( - self, - func: Callable[..., T_Retval], - args: tuple[Any, ...], - ) -> T_Retval: - raise NotImplementedError - - def destroy(self) -> None: - pass - - -DEFAULT_CPU_COUNT: Final = 8 # this is just an arbitrarily selected value -MAX_WORKER_IDLE_TIME = ( - 30 # seconds a subinterpreter can be idle before becoming eligible for pruning -) - -T_Retval = TypeVar("T_Retval") -PosArgsT = TypeVarTuple("PosArgsT") - -_idle_workers = RunVar[deque[_Worker]]("_available_workers") -_default_interpreter_limiter = RunVar[CapacityLimiter]("_default_interpreter_limiter") - - -def _stop_workers(workers: deque[_Worker]) -> None: - for worker in workers: - worker.destroy() - - workers.clear() - - -async def run_sync( - func: Callable[[Unpack[PosArgsT]], T_Retval], - *args: Unpack[PosArgsT], - limiter: CapacityLimiter | None = None, -) -> T_Retval: - """ - Call the given function with the given arguments in a subinterpreter. - - .. warning:: On Python 3.13, the :mod:`concurrent.interpreters` module was not yet - available, so the code path for that Python version relies on an undocumented, - private API. As such, it is recommended to not rely on this function for anything - mission-critical on Python 3.13. - - :param func: a callable - :param args: the positional arguments for the callable - :param limiter: capacity limiter to use to limit the total number of subinterpreters - running (if omitted, the default limiter is used) - :return: the result of the call - :raises BrokenWorkerInterpreter: if there's an internal error in a subinterpreter - - """ - if limiter is None: - limiter = current_default_interpreter_limiter() - - try: - idle_workers = _idle_workers.get() - except LookupError: - idle_workers = deque() - _idle_workers.set(idle_workers) - atexit.register(_stop_workers, idle_workers) - - async with limiter: - try: - worker = idle_workers.pop() - except IndexError: - worker = _Worker() - - try: - return await to_thread.run_sync( - worker.call, - func, - args, - limiter=limiter, - ) - finally: - # Prune workers that have been idle for too long - now = current_time() - while idle_workers: - if now - idle_workers[0].last_used <= MAX_WORKER_IDLE_TIME: - break - - await to_thread.run_sync(idle_workers.popleft().destroy, limiter=limiter) - - worker.last_used = current_time() - idle_workers.append(worker) - - -def current_default_interpreter_limiter() -> CapacityLimiter: - """ - Return the capacity limiter used by default to limit the number of concurrently - running subinterpreters. - - Defaults to the number of CPU cores. - - :return: a capacity limiter object - - """ - try: - return _default_interpreter_limiter.get() - except LookupError: - limiter = CapacityLimiter(os.cpu_count() or DEFAULT_CPU_COUNT) - _default_interpreter_limiter.set(limiter) - return limiter diff --git a/server/venv/Lib/site-packages/anyio/to_process.py b/server/venv/Lib/site-packages/anyio/to_process.py deleted file mode 100644 index fd65b18..0000000 --- a/server/venv/Lib/site-packages/anyio/to_process.py +++ /dev/null @@ -1,268 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "current_default_process_limiter", - "process_worker", - "run_sync", -) - -import os -import pickle -import runpy -import subprocess -import sys -from collections import deque -from collections.abc import Callable -from types import ModuleType -from typing import TypeVar, cast - -from ._core._eventloop import current_time, get_async_backend, get_cancelled_exc_class -from ._core._exceptions import BrokenWorkerProcess -from ._core._subprocesses import open_process -from ._core._synchronization import CapacityLimiter -from ._core._tasks import CancelScope, fail_after -from .abc import ByteReceiveStream, ByteSendStream, Process -from .lowlevel import RunVar, checkpoint_if_cancelled -from .streams.buffered import BufferedByteReceiveStream - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -WORKER_MAX_IDLE_TIME = 300 # 5 minutes - -T_Retval = TypeVar("T_Retval") -PosArgsT = TypeVarTuple("PosArgsT") - -_process_pool_workers: RunVar[set[Process]] = RunVar("_process_pool_workers") -_process_pool_idle_workers: RunVar[deque[tuple[Process, float]]] = RunVar( - "_process_pool_idle_workers" -) -_default_process_limiter: RunVar[CapacityLimiter] = RunVar("_default_process_limiter") - - -async def run_sync( # type: ignore[return] - func: Callable[[Unpack[PosArgsT]], T_Retval], - *args: Unpack[PosArgsT], - cancellable: bool = False, - limiter: CapacityLimiter | None = None, -) -> T_Retval: - """ - Call the given function with the given arguments in a worker process. - - If the ``cancellable`` option is enabled and the task waiting for its completion is - cancelled, the worker process running it will be abruptly terminated using SIGKILL - (or ``terminateProcess()`` on Windows). - - :param func: a callable - :param args: positional arguments for the callable - :param cancellable: ``True`` to allow cancellation of the operation while it's - running - :param limiter: capacity limiter to use to limit the total amount of processes - running (if omitted, the default limiter is used) - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - :return: an awaitable that yields the return value of the function. - - """ - - async def send_raw_command(pickled_cmd: bytes) -> object: - try: - await stdin.send(pickled_cmd) - response = await buffered.receive_until(b"\n", 50) - status, length = response.split(b" ") - if status not in (b"RETURN", b"EXCEPTION"): - raise RuntimeError( - f"Worker process returned unexpected response: {response!r}" - ) - - pickled_response = await buffered.receive_exactly(int(length)) - except BaseException as exc: - workers.discard(process) - try: - process.kill() - with CancelScope(shield=True): - await process.aclose() - except ProcessLookupError: - pass - - if isinstance(exc, get_cancelled_exc_class()): - raise - else: - raise BrokenWorkerProcess from exc - - retval = pickle.loads(pickled_response) - if status == b"EXCEPTION": - assert isinstance(retval, BaseException) - raise retval - else: - return retval - - # First pickle the request before trying to reserve a worker process - await checkpoint_if_cancelled() - request = pickle.dumps(("run", func, args), protocol=pickle.HIGHEST_PROTOCOL) - - # If this is the first run in this event loop thread, set up the necessary variables - try: - workers = _process_pool_workers.get() - idle_workers = _process_pool_idle_workers.get() - except LookupError: - workers = set() - idle_workers = deque() - _process_pool_workers.set(workers) - _process_pool_idle_workers.set(idle_workers) - get_async_backend().setup_process_pool_exit_at_shutdown(workers) - - async with limiter or current_default_process_limiter(): - # Pop processes from the pool (starting from the most recently used) until we - # find one that hasn't exited yet - process: Process - while idle_workers: - process, idle_since = idle_workers.pop() - if process.returncode is None: - stdin = cast(ByteSendStream, process.stdin) - buffered = BufferedByteReceiveStream( - cast(ByteReceiveStream, process.stdout) - ) - - # Prune any other workers that have been idle for WORKER_MAX_IDLE_TIME - # seconds or longer - now = current_time() - killed_processes: list[Process] = [] - while idle_workers: - if now - idle_workers[0][1] < WORKER_MAX_IDLE_TIME: - break - - process_to_kill, idle_since = idle_workers.popleft() - process_to_kill.kill() - workers.remove(process_to_kill) - killed_processes.append(process_to_kill) - - with CancelScope(shield=True): - for killed_process in killed_processes: - await killed_process.aclose() - - break - - workers.remove(process) - else: - command = [sys.executable, "-u", "-m", __name__] - process = await open_process( - command, stdin=subprocess.PIPE, stdout=subprocess.PIPE - ) - try: - stdin = cast(ByteSendStream, process.stdin) - buffered = BufferedByteReceiveStream( - cast(ByteReceiveStream, process.stdout) - ) - with fail_after(20): - message = await buffered.receive(6) - - if message != b"READY\n": - raise BrokenWorkerProcess( - f"Worker process returned unexpected response: {message!r}" - ) - - main_module_path = getattr(sys.modules["__main__"], "__file__", None) - pickled = pickle.dumps( - ("init", sys.path, main_module_path), - protocol=pickle.HIGHEST_PROTOCOL, - ) - await send_raw_command(pickled) - except (BrokenWorkerProcess, get_cancelled_exc_class()): - raise - except BaseException as exc: - process.kill() - raise BrokenWorkerProcess( - "Error during worker process initialization" - ) from exc - - workers.add(process) - - with CancelScope(shield=not cancellable): - try: - return cast(T_Retval, await send_raw_command(request)) - finally: - if process in workers: - idle_workers.append((process, current_time())) - - -def current_default_process_limiter() -> CapacityLimiter: - """ - Return the capacity limiter that is used by default to limit the number of worker - processes. - - :return: a capacity limiter object - - """ - try: - return _default_process_limiter.get() - except LookupError: - limiter = CapacityLimiter(os.cpu_count() or 2) - _default_process_limiter.set(limiter) - return limiter - - -def process_worker() -> None: - # Redirect standard streams to os.devnull so that user code won't interfere with the - # parent-worker communication - stdin = sys.stdin - stdout = sys.stdout - sys.stdin = open(os.devnull) - sys.stdout = open(os.devnull, "w") - - stdout.buffer.write(b"READY\n") - while True: - retval = exception = None - try: - command, *args = pickle.load(stdin.buffer) - except EOFError: - return - except BaseException as exc: - exception = exc - else: - if command == "run": - func, args = args - try: - retval = func(*args) - except BaseException as exc: - exception = exc - elif command == "init": - main_module_path: str | None - sys.path, main_module_path = args - del sys.modules["__main__"] - if main_module_path and os.path.isfile(main_module_path): - # Load the parent's main module but as __mp_main__ instead of - # __main__ (like multiprocessing does) to avoid infinite recursion - try: - main = ModuleType("__mp_main__") - main_content = runpy.run_path( - main_module_path, run_name="__mp_main__" - ) - main.__dict__.update(main_content) - sys.modules["__main__"] = sys.modules["__mp_main__"] = main - except BaseException as exc: - exception = exc - try: - if exception is not None: - status = b"EXCEPTION" - pickled = pickle.dumps(exception, pickle.HIGHEST_PROTOCOL) - else: - status = b"RETURN" - pickled = pickle.dumps(retval, pickle.HIGHEST_PROTOCOL) - except BaseException as exc: - exception = exc - status = b"EXCEPTION" - pickled = pickle.dumps(exc, pickle.HIGHEST_PROTOCOL) - - stdout.buffer.write(b"%s %d\n" % (status, len(pickled))) - stdout.buffer.write(pickled) - - # Respect SIGTERM - if isinstance(exception, SystemExit): - raise exception - - -if __name__ == "__main__": - process_worker() diff --git a/server/venv/Lib/site-packages/anyio/to_thread.py b/server/venv/Lib/site-packages/anyio/to_thread.py deleted file mode 100644 index 83c79d1..0000000 --- a/server/venv/Lib/site-packages/anyio/to_thread.py +++ /dev/null @@ -1,78 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "run_sync", - "current_default_thread_limiter", -) - -import sys -from collections.abc import Callable -from typing import TypeVar -from warnings import warn - -from ._core._eventloop import get_async_backend -from .abc import CapacityLimiter - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -T_Retval = TypeVar("T_Retval") -PosArgsT = TypeVarTuple("PosArgsT") - - -async def run_sync( - func: Callable[[Unpack[PosArgsT]], T_Retval], - *args: Unpack[PosArgsT], - abandon_on_cancel: bool = False, - cancellable: bool | None = None, - limiter: CapacityLimiter | None = None, -) -> T_Retval: - """ - Call the given function with the given arguments in a worker thread. - - If the ``abandon_on_cancel`` option is enabled and the task waiting for its - completion is cancelled, the thread will still run its course but its - return value (or any raised exception) will be ignored. - - :param func: a callable - :param args: positional arguments for the callable - :param abandon_on_cancel: ``True`` to abandon the thread (leaving it to run - unchecked on own) if the host task is cancelled, ``False`` to ignore - cancellations in the host task until the operation has completed in the worker - thread - :param cancellable: deprecated alias of ``abandon_on_cancel``; will override - ``abandon_on_cancel`` if both parameters are passed - :param limiter: capacity limiter to use to limit the total amount of threads running - (if omitted, the default limiter is used) - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - :return: an awaitable that yields the return value of the function. - - """ - if cancellable is not None: - abandon_on_cancel = cancellable - warn( - "The `cancellable=` keyword argument to `anyio.to_thread.run_sync` is " - "deprecated since AnyIO 4.1.0; use `abandon_on_cancel=` instead", - DeprecationWarning, - stacklevel=2, - ) - - return await get_async_backend().run_sync_in_worker_thread( - func, args, abandon_on_cancel=abandon_on_cancel, limiter=limiter - ) - - -def current_default_thread_limiter() -> CapacityLimiter: - """ - Return the capacity limiter that is used by default to limit the number of - concurrent threads. - - :return: a capacity limiter object - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().current_default_thread_limiter() diff --git a/server/venv/Lib/site-packages/click-8.4.1.dist-info/INSTALLER b/server/venv/Lib/site-packages/click-8.4.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/server/venv/Lib/site-packages/click-8.4.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/server/venv/Lib/site-packages/click-8.4.1.dist-info/METADATA b/server/venv/Lib/site-packages/click-8.4.1.dist-info/METADATA deleted file mode 100644 index 21d7a0c..0000000 --- a/server/venv/Lib/site-packages/click-8.4.1.dist-info/METADATA +++ /dev/null @@ -1,84 +0,0 @@ -Metadata-Version: 2.4 -Name: click -Version: 8.4.1 -Summary: Composable command line interface toolkit -Maintainer-email: Pallets -Requires-Python: >=3.10 -Description-Content-Type: text/markdown -License-Expression: BSD-3-Clause -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Typing :: Typed -License-File: LICENSE.txt -Requires-Dist: colorama; platform_system == 'Windows' -Project-URL: Changes, https://click.palletsprojects.com/page/changes/ -Project-URL: Chat, https://discord.gg/pallets -Project-URL: Documentation, https://click.palletsprojects.com/ -Project-URL: Donate, https://palletsprojects.com/donate -Project-URL: Source, https://github.com/pallets/click/ - -
- -# Click - -Click is a Python package for creating beautiful command line interfaces -in a composable way with as little code as necessary. It's the "Command -Line Interface Creation Kit". It's highly configurable but comes with -sensible defaults out of the box. - -It aims to make the process of writing command line tools quick and fun -while also preventing any frustration caused by the inability to -implement an intended CLI API. - -Click in three points: - -- Arbitrary nesting of commands -- Automatic help page generation -- Supports lazy loading of subcommands at runtime - - -## A Simple Example - -```python -import click - -@click.command() -@click.option("--count", default=1, help="Number of greetings.") -@click.option("--name", prompt="Your name", help="The person to greet.") -def hello(count, name): - """Simple program that greets NAME for a total of COUNT times.""" - for _ in range(count): - click.echo(f"Hello, {name}!") - -if __name__ == '__main__': - hello() -``` - -``` -$ python hello.py --count=3 -Your name: Click -Hello, Click! -Hello, Click! -Hello, Click! -``` - - -## Donate - -The Pallets organization develops and supports Click and other popular -packages. In order to grow the community of contributors and users, and -allow the maintainers to devote more time to the projects, [please -donate today][]. - -[please donate today]: https://palletsprojects.com/donate - -## Contributing - -See our [detailed contributing documentation][contrib] for many ways to -contribute, including reporting issues, requesting features, asking or answering -questions, and making PRs. - -[contrib]: https://palletsprojects.com/contributing/ - diff --git a/server/venv/Lib/site-packages/click-8.4.1.dist-info/RECORD b/server/venv/Lib/site-packages/click-8.4.1.dist-info/RECORD deleted file mode 100644 index e84fda1..0000000 --- a/server/venv/Lib/site-packages/click-8.4.1.dist-info/RECORD +++ /dev/null @@ -1,40 +0,0 @@ -click-8.4.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -click-8.4.1.dist-info/METADATA,sha256=uWALc7Y-Ixjj35al3B2qNsyXk-0tf578YgIsL1Vbn98,2621 -click-8.4.1.dist-info/RECORD,, -click-8.4.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 -click-8.4.1.dist-info/licenses/LICENSE.txt,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 -click/__init__.py,sha256=FId2fXCSJB3yeWD-e2uON-mBhFa2Yc9MvXGmHu8OXG0,4634 -click/__pycache__/__init__.cpython-313.pyc,, -click/__pycache__/_compat.cpython-313.pyc,, -click/__pycache__/_termui_impl.cpython-313.pyc,, -click/__pycache__/_textwrap.cpython-313.pyc,, -click/__pycache__/_utils.cpython-313.pyc,, -click/__pycache__/_winconsole.cpython-313.pyc,, -click/__pycache__/core.cpython-313.pyc,, -click/__pycache__/decorators.cpython-313.pyc,, -click/__pycache__/exceptions.cpython-313.pyc,, -click/__pycache__/formatting.cpython-313.pyc,, -click/__pycache__/globals.cpython-313.pyc,, -click/__pycache__/parser.cpython-313.pyc,, -click/__pycache__/shell_completion.cpython-313.pyc,, -click/__pycache__/termui.cpython-313.pyc,, -click/__pycache__/testing.cpython-313.pyc,, -click/__pycache__/types.cpython-313.pyc,, -click/__pycache__/utils.cpython-313.pyc,, -click/_compat.py,sha256=XK1woqBSPRb1KNAwWwVsSMfEm8ZlfDwBCjceWzSGmEY,18910 -click/_termui_impl.py,sha256=VNyWY27pm0JUq12WK__pJNYxeUoDyfNwYEgE6vz_cnM,30411 -click/_textwrap.py,sha256=7Z0N7Vmn-66TNSTUwp6OXJbcUXRmYET9h9c2ucD8oQQ,6270 -click/_utils.py,sha256=eCZCtwJtsYD5QYkkNWJ8MY_8ABIjy8MczgMMyVY32rQ,996 -click/_winconsole.py,sha256=KSxfNbMlYRa6GOJuCLgsg2Pb3dVkgJNPqLJPae-Pa10,8543 -click/core.py,sha256=CQaJ0ALw4zyyVp6E7gP6a_G88eiuXE9mBzFnIJQ-igY,137917 -click/decorators.py,sha256=xgR8vZAClhWVkzitP22k6jETFRhKralh81zvA69Csd0,18467 -click/exceptions.py,sha256=FJitDd6MSZLj6CtKQWpkQzHnfsUw3UypxDU0t76bn0c,11294 -click/formatting.py,sha256=r6kGLpPyF0Cva6uSTwSZ_8ONRE7jp93I1C0JVRYQEqE,10370 -click/globals.py,sha256=gM-Nh6A4M0HB_SgkaF5M4ncGGMDHc_flHXu9_oh4GEU,1923 -click/parser.py,sha256=oJ-fU_3mvxugIuNtHaCATZ56lgEmHRggjJiSqEgYrjA,19052 -click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -click/shell_completion.py,sha256=QxeFb3RapNSP8ZwvK2BDVI2jrEKS1RbJaeuFMrHJAnU,21748 -click/termui.py,sha256=hflZ_tK7P4WUv_ef_RVVRL7n0nRPhTD0wN0pkHE7hDo,33000 -click/testing.py,sha256=0k_v5By_5ZO2McjBT7lTqQ57W8QJuW0_5Sx7d2ZLKec,25717 -click/types.py,sha256=UiVEx0yoQtrWO2wH22NgME4LfDxMNQi8j1qtJupYIpw,42783 -click/utils.py,sha256=YsTNrChEfwDXl39CTC_yWnQ-ZVkZxYjFESRCfEgClY4,20386 diff --git a/server/venv/Lib/site-packages/click-8.4.1.dist-info/WHEEL b/server/venv/Lib/site-packages/click-8.4.1.dist-info/WHEEL deleted file mode 100644 index d8b9936..0000000 --- a/server/venv/Lib/site-packages/click-8.4.1.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: flit 3.12.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/server/venv/Lib/site-packages/click-8.4.1.dist-info/licenses/LICENSE.txt b/server/venv/Lib/site-packages/click-8.4.1.dist-info/licenses/LICENSE.txt deleted file mode 100644 index d12a849..0000000 --- a/server/venv/Lib/site-packages/click-8.4.1.dist-info/licenses/LICENSE.txt +++ /dev/null @@ -1,28 +0,0 @@ -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/server/venv/Lib/site-packages/click/__init__.py b/server/venv/Lib/site-packages/click/__init__.py deleted file mode 100644 index 64be7e0..0000000 --- a/server/venv/Lib/site-packages/click/__init__.py +++ /dev/null @@ -1,126 +0,0 @@ -""" -Click is a simple Python module inspired by the stdlib optparse to make -writing command line scripts fun. Unlike other modules, it's based -around a simple API that does not come with too much magic and is -composable. -""" - -from __future__ import annotations - -from .core import Argument as Argument -from .core import Command as Command -from .core import CommandCollection as CommandCollection -from .core import Context as Context -from .core import Group as Group -from .core import Option as Option -from .core import Parameter as Parameter -from .core import ParameterSource as ParameterSource -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 NoSuchCommand as NoSuchCommand -from .exceptions import NoSuchOption as NoSuchOption -from .exceptions import UsageError as UsageError -from .formatting import HelpFormatter as HelpFormatter -from .formatting import wrap_text as wrap_text -from .globals import get_current_context as get_current_context -from .termui import clear as clear -from .termui import confirm as confirm -from .termui import echo_via_pager as echo_via_pager -from .termui import edit as edit -from .termui import get_pager_file as get_pager_file -from .termui import getchar as getchar -from .termui import launch as launch -from .termui import pause as pause -from .termui import progressbar as progressbar -from .termui import prompt as prompt -from .termui import secho as secho -from .termui import style as style -from .termui import unstyle as unstyle -from .types import BOOL as BOOL -from .types import Choice as Choice -from .types import DateTime as DateTime -from .types import File as File -from .types import FLOAT as FLOAT -from .types import FloatRange as FloatRange -from .types import INT as INT -from .types import IntRange as IntRange -from .types import ParamType as ParamType -from .types import Path as Path -from .types import STRING as STRING -from .types import Tuple as Tuple -from .types import UNPROCESSED as UNPROCESSED -from .types import UUID as UUID -from .utils import echo as echo -from .utils import format_filename as format_filename -from .utils import get_app_dir as get_app_dir -from .utils import get_binary_stream as get_binary_stream -from .utils import get_text_stream as get_text_stream -from .utils import open_file as open_file - - -def __getattr__(name: str) -> object: - import warnings - - if name == "BaseCommand": - from .core import _BaseCommand - - warnings.warn( - "'BaseCommand' is deprecated and will be removed in Click 9.0. Use" - " 'Command' instead.", - DeprecationWarning, - stacklevel=2, - ) - return _BaseCommand - - if name == "MultiCommand": - from .core import _MultiCommand - - warnings.warn( - "'MultiCommand' is deprecated and will be removed in Click 9.0. Use" - " 'Group' instead.", - DeprecationWarning, - stacklevel=2, - ) - return _MultiCommand - - if name == "OptionParser": - from .parser import _OptionParser - - warnings.warn( - "'OptionParser' is deprecated and will be removed in Click 9.0. The" - " old parser is available in 'optparse'.", - DeprecationWarning, - stacklevel=2, - ) - return _OptionParser - - if name == "__version__": - import importlib.metadata - import warnings - - warnings.warn( - "The '__version__' attribute is deprecated and will be removed in" - " Click 9.1. Use feature detection or" - " 'importlib.metadata.version(\"click\")' instead.", - DeprecationWarning, - stacklevel=2, - ) - return importlib.metadata.version("click") - - raise AttributeError(name) diff --git a/server/venv/Lib/site-packages/click/_compat.py b/server/venv/Lib/site-packages/click/_compat.py deleted file mode 100644 index 36c0e53..0000000 --- a/server/venv/Lib/site-packages/click/_compat.py +++ /dev/null @@ -1,627 +0,0 @@ -from __future__ import annotations - -import codecs -import collections.abc as cabc -import io -import os -import re -import sys -import typing as t -from types import TracebackType -from weakref import WeakKeyDictionary - -CYGWIN = sys.platform.startswith("cygwin") -WIN = sys.platform.startswith("win") -MAC = sys.platform == "darwin" -auto_wrap_for_ansi: t.Callable[[t.TextIO], t.TextIO] | None = None -_ansi_re = re.compile(r"\033\[[;?0-9]*[a-zA-Z]") - - -def _make_text_stream( - stream: t.BinaryIO, - encoding: str | None, - errors: str | None, - force_readable: bool = False, - force_writable: bool = False, -) -> t.TextIO: - if encoding is None: - encoding = get_best_encoding(stream) - if errors is None: - errors = "replace" - return _NonClosingTextIOWrapper( - stream, - encoding, - errors, - line_buffering=True, - force_readable=force_readable, - force_writable=force_writable, - ) - - -def is_ascii_encoding(encoding: str) -> bool: - """Checks if a given encoding is ascii.""" - try: - return codecs.lookup(encoding).name == "ascii" - except LookupError: - return False - - -def get_best_encoding(stream: t.IO[t.Any]) -> str: - """Returns the default stream encoding if not found.""" - rv = getattr(stream, "encoding", None) or sys.getdefaultencoding() - if is_ascii_encoding(rv): - return "utf-8" - return rv - - -class _NonClosingTextIOWrapper(io.TextIOWrapper): - def __init__( - self, - stream: t.BinaryIO, - encoding: str | None, - errors: str | None, - force_readable: bool = False, - force_writable: bool = False, - **extra: t.Any, - ) -> None: - self._stream = stream = t.cast( - t.BinaryIO, _FixupStream(stream, force_readable, force_writable) - ) - super().__init__(stream, encoding, errors, **extra) - - def __del__(self) -> None: - try: - self.detach() - except Exception: - pass - - def isatty(self) -> bool: - # https://bitbucket.org/pypy/pypy/issue/1803 - return self._stream.isatty() - - -class _FixupStream: - """The new io interface needs more from streams than streams - traditionally implement. As such, this fix-up code is necessary in - some circumstances. - - The forcing of readable and writable flags are there because some tools - put badly patched objects on sys (one such offender are certain version - of jupyter notebook). - """ - - def __init__( - self, - stream: t.BinaryIO, - force_readable: bool = False, - force_writable: bool = False, - ): - self._stream = stream - self._force_readable = force_readable - self._force_writable = force_writable - - def __getattr__(self, name: str) -> t.Any: - return getattr(self._stream, name) - - def read1(self, size: int) -> bytes: - f = getattr(self._stream, "read1", None) - - if f is not None: - return t.cast(bytes, f(size)) - - return self._stream.read(size) - - def readable(self) -> bool: - if self._force_readable: - return True - x = getattr(self._stream, "readable", None) - if x is not None: - return t.cast(bool, x()) - try: - self._stream.read(0) - except Exception: - return False - return True - - def writable(self) -> bool: - if self._force_writable: - return True - x = getattr(self._stream, "writable", None) - if x is not None: - return t.cast(bool, x()) - try: - self._stream.write(b"") - except Exception: - try: - self._stream.write(b"") - except Exception: - return False - return True - - def seekable(self) -> bool: - x = getattr(self._stream, "seekable", None) - if x is not None: - return t.cast(bool, x()) - try: - self._stream.seek(self._stream.tell()) - except Exception: - return False - return True - - -def _is_binary_reader(stream: t.IO[t.Any], default: bool = False) -> bool: - try: - return isinstance(stream.read(0), bytes) - except Exception: - return default - # This happens in some cases where the stream was already - # closed. In this case, we assume the default. - - -def _is_binary_writer(stream: t.IO[t.Any], default: bool = False) -> bool: - try: - stream.write(b"") - except Exception: - try: - stream.write("") - return False - except Exception: - pass - return default - return True - - -def _find_binary_reader(stream: t.IO[t.Any]) -> t.BinaryIO | None: - # We need to figure out if the given stream is already binary. - # This can happen because the official docs recommend detaching - # the streams to get binary streams. Some code might do this, so - # we need to deal with this case explicitly. - if _is_binary_reader(stream, False): - return t.cast(t.BinaryIO, stream) - - buf = getattr(stream, "buffer", None) - - # Same situation here; this time we assume that the buffer is - # actually binary in case it's closed. - if buf is not None and _is_binary_reader(buf, True): - return t.cast(t.BinaryIO, buf) - - return None - - -def _find_binary_writer(stream: t.IO[t.Any]) -> t.BinaryIO | None: - # We need to figure out if the given stream is already binary. - # This can happen because the official docs recommend detaching - # the streams to get binary streams. Some code might do this, so - # we need to deal with this case explicitly. - if _is_binary_writer(stream, False): - return t.cast(t.BinaryIO, stream) - - buf = getattr(stream, "buffer", None) - - # Same situation here; this time we assume that the buffer is - # actually binary in case it's closed. - if buf is not None and _is_binary_writer(buf, True): - return t.cast(t.BinaryIO, buf) - - return None - - -def _stream_is_misconfigured(stream: t.TextIO) -> bool: - """A stream is misconfigured if its encoding is ASCII.""" - # If the stream does not have an encoding set, we assume it's set - # to ASCII. This appears to happen in certain unittest - # environments. It's not quite clear what the correct behavior is - # but this at least will force Click to recover somehow. - return is_ascii_encoding(getattr(stream, "encoding", None) or "ascii") - - -def _is_compat_stream_attr(stream: t.TextIO, attr: str, value: str | None) -> bool: - """A stream attribute is compatible if it is equal to the - desired value or the desired value is unset and the attribute - has a value. - """ - stream_value = getattr(stream, attr, None) - return stream_value == value or (value is None and stream_value is not None) - - -def _is_compatible_text_stream( - stream: t.TextIO, encoding: str | None, errors: str | None -) -> bool: - """Check if a stream's encoding and errors attributes are - compatible with the desired values. - """ - return _is_compat_stream_attr( - stream, "encoding", encoding - ) and _is_compat_stream_attr(stream, "errors", errors) - - -def _force_correct_text_stream( - text_stream: t.IO[t.Any], - encoding: str | None, - errors: str | None, - is_binary: t.Callable[[t.IO[t.Any], bool], bool], - find_binary: t.Callable[[t.IO[t.Any]], t.BinaryIO | None], - force_readable: bool = False, - force_writable: bool = False, -) -> t.TextIO: - if is_binary(text_stream, False): - binary_reader = t.cast(t.BinaryIO, text_stream) - else: - text_stream = t.cast(t.TextIO, text_stream) - # If the stream looks compatible, and won't default to a - # misconfigured ascii encoding, return it as-is. - if _is_compatible_text_stream(text_stream, encoding, errors) and not ( - encoding is None and _stream_is_misconfigured(text_stream) - ): - return text_stream - - # Otherwise, get the underlying binary reader. - possible_binary_reader = find_binary(text_stream) - - # If that's not possible, silently use the original reader - # and get mojibake instead of exceptions. - if possible_binary_reader is None: - return text_stream - - binary_reader = possible_binary_reader - - # Default errors to replace instead of strict in order to get - # something that works. - if errors is None: - errors = "replace" - - # Wrap the binary stream in a text stream with the correct - # encoding parameters. - return _make_text_stream( - binary_reader, - encoding, - errors, - force_readable=force_readable, - force_writable=force_writable, - ) - - -def _force_correct_text_reader( - text_reader: t.IO[t.Any], - encoding: str | None, - errors: str | None, - force_readable: bool = False, -) -> t.TextIO: - return _force_correct_text_stream( - text_reader, - encoding, - errors, - _is_binary_reader, - _find_binary_reader, - force_readable=force_readable, - ) - - -def _force_correct_text_writer( - text_writer: t.IO[t.Any], - encoding: str | None, - errors: str | None, - force_writable: bool = False, -) -> t.TextIO: - return _force_correct_text_stream( - text_writer, - encoding, - errors, - _is_binary_writer, - _find_binary_writer, - force_writable=force_writable, - ) - - -def get_binary_stdin() -> t.BinaryIO: - reader = _find_binary_reader(sys.stdin) - if reader is None: - raise RuntimeError("Was not able to determine binary stream for sys.stdin.") - return reader - - -def get_binary_stdout() -> t.BinaryIO: - writer = _find_binary_writer(sys.stdout) - if writer is None: - raise RuntimeError("Was not able to determine binary stream for sys.stdout.") - return writer - - -def get_binary_stderr() -> t.BinaryIO: - writer = _find_binary_writer(sys.stderr) - if writer is None: - raise RuntimeError("Was not able to determine binary stream for sys.stderr.") - return writer - - -def get_text_stdin(encoding: str | None = None, errors: str | None = None) -> t.TextIO: - rv = _get_windows_console_stream(sys.stdin, encoding, errors) - if rv is not None: - return rv - return _force_correct_text_reader(sys.stdin, encoding, errors, force_readable=True) - - -def get_text_stdout(encoding: str | None = None, errors: str | None = None) -> t.TextIO: - rv = _get_windows_console_stream(sys.stdout, encoding, errors) - if rv is not None: - return rv - return _force_correct_text_writer(sys.stdout, encoding, errors, force_writable=True) - - -def get_text_stderr(encoding: str | None = None, errors: str | None = None) -> t.TextIO: - rv = _get_windows_console_stream(sys.stderr, encoding, errors) - if rv is not None: - return rv - return _force_correct_text_writer(sys.stderr, encoding, errors, force_writable=True) - - -def _wrap_io_open( - file: str | os.PathLike[str] | int, - mode: str, - encoding: str | None, - errors: str | None, -) -> t.IO[t.Any]: - """Handles not passing ``encoding`` and ``errors`` in binary mode.""" - if "b" in mode: - return open(file, mode) - - return open(file, mode, encoding=encoding, errors=errors) - - -def open_stream( - filename: str | os.PathLike[str], - mode: str = "r", - encoding: str | None = None, - errors: str | None = "strict", - atomic: bool = False, -) -> tuple[t.IO[t.Any], bool]: - binary = "b" in mode - filename = os.fspath(filename) - - # Standard streams first. These are simple because they ignore the - # atomic flag. Use fsdecode to handle Path("-"). - if os.fsdecode(filename) == "-": - if any(m in mode for m in ["w", "a", "x"]): - if binary: - return get_binary_stdout(), False - return get_text_stdout(encoding=encoding, errors=errors), False - if binary: - return get_binary_stdin(), False - return get_text_stdin(encoding=encoding, errors=errors), False - - # Non-atomic writes directly go out through the regular open functions. - if not atomic: - return _wrap_io_open(filename, mode, encoding, errors), True - - # Some usability stuff for atomic writes - if "a" in mode: - raise ValueError( - "Appending to an existing file is not supported, because that" - " would involve an expensive `copy`-operation to a temporary" - " file. Open the file in normal `w`-mode and copy explicitly" - " if that's what you're after." - ) - if "x" in mode: - raise ValueError("Use the `overwrite`-parameter instead.") - if "w" not in mode: - raise ValueError("Atomic writes only make sense with `w`-mode.") - - # Atomic writes are more complicated. They work by opening a file - # as a proxy in the same folder and then using the fdopen - # functionality to wrap it in a Python file. Then we wrap it in an - # atomic file that moves the file over on close. - import errno - import random - - try: - perm: int | None = os.stat(filename).st_mode - except OSError: - perm = None - - flags = os.O_RDWR | os.O_CREAT | os.O_EXCL - - if binary: - flags |= getattr(os, "O_BINARY", 0) - - while True: - tmp_filename = os.path.join( - os.path.dirname(filename), - f".__atomic-write{random.randrange(1 << 32):08x}", - ) - try: - fd = os.open(tmp_filename, flags, 0o666 if perm is None else perm) - break - except OSError as e: - if e.errno == errno.EEXIST or ( - os.name == "nt" - and e.errno == errno.EACCES - and os.path.isdir(e.filename) - and os.access(e.filename, os.W_OK) - ): - continue - raise - - if perm is not None: - os.chmod(tmp_filename, perm) # in case perm includes bits in umask - - f = _wrap_io_open(fd, mode, encoding, errors) - af = _AtomicFile(f, tmp_filename, os.path.realpath(filename)) - return t.cast(t.IO[t.Any], af), True - - -class _AtomicFile: - def __init__(self, f: t.IO[t.Any], tmp_filename: str, real_filename: str) -> None: - self._f = f - self._tmp_filename = tmp_filename - self._real_filename = real_filename - self.closed = False - - @property - def name(self) -> str: - return self._real_filename - - def close(self, delete: bool = False) -> None: - if self.closed: - return - self._f.close() - os.replace(self._tmp_filename, self._real_filename) - self.closed = True - - def __getattr__(self, name: str) -> t.Any: - return getattr(self._f, name) - - def __enter__(self) -> _AtomicFile: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - tb: TracebackType | None, - ) -> None: - self.close(delete=exc_type is not None) - - def __repr__(self) -> str: - return repr(self._f) - - -def strip_ansi(value: str) -> str: - return _ansi_re.sub("", value) - - -def _is_jupyter_kernel_output(stream: t.IO[t.Any]) -> bool: - while isinstance(stream, (_FixupStream, _NonClosingTextIOWrapper)): - stream = stream._stream - - return stream.__class__.__module__.startswith("ipykernel.") - - -def should_strip_ansi( - stream: t.IO[t.Any] | None = None, color: bool | None = None -) -> bool: - if color is None: - if stream is None: - stream = sys.stdin - elif hasattr(stream, "color"): - # ._termui_impl.MaybeStripAnsi handles stripping ansi itself, - # so we don't need to strip it here - return False - return not isatty(stream) and not _is_jupyter_kernel_output(stream) - return not color - - -# On Windows, wrap the output streams with colorama to support ANSI -# color codes. -# NOTE: double check is needed so mypy does not analyze this on Linux -if sys.platform.startswith("win") and WIN: - from ._winconsole import _get_windows_console_stream - - def _get_argv_encoding() -> str: - import locale - - return locale.getpreferredencoding() - - _ansi_stream_wrappers: cabc.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() - - def auto_wrap_for_ansi(stream: t.TextIO, color: bool | None = None) -> t.TextIO: - """Support ANSI color and style codes on Windows by wrapping a - stream with colorama. - """ - try: - cached = _ansi_stream_wrappers.get(stream) - except Exception: - cached = None - - if cached is not None: - return cached - - import colorama - - strip = should_strip_ansi(stream, color) - ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip) - rv = t.cast(t.TextIO, ansi_wrapper.stream) - _write = rv.write - - def _safe_write(s: str) -> int: - try: - return _write(s) - except BaseException: - ansi_wrapper.reset_all() - raise - - rv.write = _safe_write # type: ignore[method-assign] - - try: - _ansi_stream_wrappers[stream] = rv - except Exception: - pass - - return rv - -else: - - def _get_argv_encoding() -> str: - return getattr(sys.stdin, "encoding", None) or sys.getfilesystemencoding() - - def _get_windows_console_stream( - f: t.TextIO, encoding: str | None, errors: str | None - ) -> t.TextIO | None: - return None - - -def term_len(x: str) -> int: - return len(strip_ansi(x)) - - -def isatty(stream: t.IO[t.Any]) -> bool: - try: - return stream.isatty() - except Exception: - return False - - -def _make_cached_stream_func( - src_func: t.Callable[[], t.TextIO | None], - wrapper_func: t.Callable[[], t.TextIO], -) -> t.Callable[[], t.TextIO | None]: - cache: cabc.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() - - def func() -> t.TextIO | None: - stream = src_func() - - if stream is None: - return None - - try: - rv = cache.get(stream) - except Exception: - rv = None - if rv is not None: - return rv - rv = wrapper_func() - try: - cache[stream] = rv - except Exception: - pass - return rv - - return func - - -_default_text_stdin = _make_cached_stream_func(lambda: sys.stdin, get_text_stdin) -_default_text_stdout = _make_cached_stream_func(lambda: sys.stdout, get_text_stdout) -_default_text_stderr = _make_cached_stream_func(lambda: sys.stderr, get_text_stderr) - - -binary_streams: cabc.Mapping[str, t.Callable[[], t.BinaryIO]] = { - "stdin": get_binary_stdin, - "stdout": get_binary_stdout, - "stderr": get_binary_stderr, -} - -text_streams: cabc.Mapping[str, t.Callable[[str | None, str | None], t.TextIO]] = { - "stdin": get_text_stdin, - "stdout": get_text_stdout, - "stderr": get_text_stderr, -} diff --git a/server/venv/Lib/site-packages/click/_termui_impl.py b/server/venv/Lib/site-packages/click/_termui_impl.py deleted file mode 100644 index 76113e9..0000000 --- a/server/venv/Lib/site-packages/click/_termui_impl.py +++ /dev/null @@ -1,929 +0,0 @@ -""" -This module contains implementations for the termui module. To keep the -import time of Click down, some infrequently used functionality is -placed in this module and only imported as needed. -""" - -from __future__ import annotations - -import collections.abc as cabc -import contextlib -import io -import math -import os -import shlex -import sys -import time -import typing as t -from gettext import gettext as _ -from io import StringIO -from pathlib import Path -from types import TracebackType - -from ._compat import _default_text_stdout -from ._compat import CYGWIN -from ._compat import get_best_encoding -from ._compat import isatty -from ._compat import strip_ansi -from ._compat import term_len -from ._compat import WIN -from .exceptions import ClickException -from .utils import echo - -V = t.TypeVar("V") - - -class _BufferedTextPagerStream(t.Protocol): - buffer: t.BinaryIO - - -def _has_binary_buffer( - stream: t.BinaryIO | t.TextIO, -) -> t.TypeGuard[_BufferedTextPagerStream]: - # TextIO is wider than TextIOWrapper; text-only streams such as StringIO - # are valid TextIO values but do not expose a binary buffer to wrap. - return getattr(stream, "buffer", None) is not None - - -if os.name == "nt": - BEFORE_BAR = "\r" - AFTER_BAR = "\n" -else: - BEFORE_BAR = "\r\033[?25l" - AFTER_BAR = "\033[?25h\n" - - -class ProgressBar(t.Generic[V]): - def __init__( - self, - iterable: cabc.Iterable[V] | None, - length: int | None = None, - fill_char: str = "#", - empty_char: str = " ", - bar_template: str = "%(bar)s", - info_sep: str = " ", - hidden: bool = False, - show_eta: bool = True, - show_percent: bool | None = None, - show_pos: bool = False, - item_show_func: t.Callable[[V | None], str | None] | None = None, - label: str | None = None, - file: t.TextIO | None = None, - color: bool | None = None, - update_min_steps: int = 1, - width: int = 30, - ) -> None: - self.fill_char = fill_char - self.empty_char = empty_char - self.bar_template = bar_template - self.info_sep = info_sep - self.hidden = hidden - self.show_eta = show_eta - self.show_percent = show_percent - self.show_pos = show_pos - self.item_show_func = item_show_func - self.label: str = label or "" - - if file is None: - file = _default_text_stdout() - - # There are no standard streams attached to write to. For example, - # pythonw on Windows. - if file is None: - file = StringIO() - - self.file = file - self.color = color - self.update_min_steps = update_min_steps - self._completed_intervals = 0 - self.width: int = width - self.autowidth: bool = width == 0 - - if length is None: - from operator import length_hint - - length = length_hint(iterable, -1) - - if length == -1: - length = None - if iterable is None: - if length is None: - raise TypeError("iterable or length is required") - iterable = t.cast("cabc.Iterable[V]", range(length)) - self.iter: cabc.Iterable[V] = iter(iterable) - self.length = length - self.pos: int = 0 - self.avg: list[float] = [] - self.last_eta: float - self.start: float - self.start = self.last_eta = time.time() - self.eta_known: bool = False - self.finished: bool = False - self.max_width: int | None = None - self.entered: bool = False - self.current_item: V | None = None - self._is_atty = isatty(self.file) - self._last_line: str | None = None - - def __enter__(self) -> ProgressBar[V]: - self.entered = True - self.render_progress() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - tb: TracebackType | None, - ) -> None: - self.render_finish() - - def __iter__(self) -> cabc.Iterator[V]: - if not self.entered: - raise RuntimeError("You need to use progress bars in a with block.") - self.render_progress() - return self.generator() - - def __next__(self) -> V: - # Iteration is defined in terms of a generator function, - # returned by iter(self); use that to define next(). This works - # because `self.iter` is an iterable consumed by that generator, - # so it is re-entry safe. Calling `next(self.generator())` - # twice works and does "what you want". - return next(iter(self)) - - def render_finish(self) -> None: - if self.hidden or not self._is_atty: - return - self.file.write(AFTER_BAR) - self.file.flush() - - @property - def pct(self) -> float: - if self.finished: - return 1.0 - return min(self.pos / (float(self.length or 1) or 1), 1.0) - - @property - def time_per_iteration(self) -> float: - if not self.avg: - return 0.0 - return sum(self.avg) / float(len(self.avg)) - - @property - def eta(self) -> float: - if self.length is not None and not self.finished: - return self.time_per_iteration * (self.length - self.pos) - return 0.0 - - def format_eta(self) -> str: - if self.eta_known: - t = int(self.eta) - seconds = t % 60 - t //= 60 - minutes = t % 60 - t //= 60 - hours = t % 24 - t //= 24 - if t > 0: - return "{d}{day_label} {h:02}:{m:02}:{s:02}".format( - d=t, - day_label=_("d"), - h=hours, - m=minutes, - s=seconds, - ) - 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: - if self.hidden: - return - - if not self._is_atty: - # Only output the label once if the output is not a TTY. - if self._last_line != self.label: - self._last_line = self.label - echo(self.label, file=self.file, color=self.color) - return - - buf = [] - # Update width in case the terminal has been resized - if self.autowidth: - import shutil - - old_width = self.width - self.width = 0 - clutter_length = term_len(self.format_progress_line()) - new_width = max(0, shutil.get_terminal_size().columns - clutter_length) - if new_width < old_width and self.max_width is not None: - buf.append(BEFORE_BAR) - buf.append(" " * self.max_width) - self.max_width = new_width - self.width = new_width - - clear_width = self.width - if self.max_width is not None: - clear_width = self.max_width - - buf.append(BEFORE_BAR) - line = self.format_progress_line() - line_len = term_len(line) - if self.max_width is None or self.max_width < line_len: - self.max_width = line_len - - buf.append(line) - buf.append(" " * (clear_width - line_len)) - line = "".join(buf) - # Render the line only if it changed. - - if line != self._last_line: - self._last_line = line - echo(line, file=self.file, color=self.color, nl=False) - self.file.flush() - - def make_step(self, n_steps: int) -> None: - self.pos += n_steps - if self.length is not None and self.pos >= self.length: - self.finished = True - - if (time.time() - self.last_eta) < 1.0: - return - - self.last_eta = time.time() - - # self.avg is a rolling list of length <= 7 of steps where steps are - # defined as time elapsed divided by the total progress through - # self.length. - if self.pos: - step = (time.time() - self.start) / self.pos - else: - step = time.time() - self.start - - self.avg = self.avg[-6:] + [step] - - self.eta_known = self.length is not None - - def update(self, n_steps: int, current_item: V | None = None) -> None: - """Update the progress bar by advancing a specified number of - steps, and optionally set the ``current_item`` for this new - position. - - :param n_steps: Number of steps to advance. - :param current_item: Optional item to set as ``current_item`` - for the updated position. - - .. versionchanged:: 8.0 - Added the ``current_item`` optional parameter. - - .. versionchanged:: 8.0 - Only render when the number of steps meets the - ``update_min_steps`` threshold. - """ - if current_item is not None: - self.current_item = current_item - - self._completed_intervals += n_steps - - if self._completed_intervals >= self.update_min_steps: - self.make_step(self._completed_intervals) - self.render_progress() - self._completed_intervals = 0 - - def finish(self) -> None: - self.eta_known = False - self.current_item = None - self.finished = True - - def generator(self) -> cabc.Iterator[V]: - """Return a generator which yields the items added to the bar - during construction, and updates the progress bar *after* the - yielded block returns. - """ - # WARNING: the iterator interface for `ProgressBar` relies on - # this and only works because this is a simple generator which - # doesn't create or manage additional state. If this function - # changes, the impact should be evaluated both against - # `iter(bar)` and `next(bar)`. `next()` in particular may call - # `self.generator()` repeatedly, and this must remain safe in - # order for that interface to work. - if not self.entered: - raise RuntimeError("You need to use progress bars in a with block.") - - if not self._is_atty: - yield from self.iter - else: - for rv in self.iter: - self.current_item = rv - - # This allows show_item_func to be updated before the - # item is processed. Only trigger at the beginning of - # the update interval. - if self._completed_intervals == 0: - self.render_progress() - - yield rv - self.update(1) - - self.finish() - self.render_progress() - - -class MaybeStripAnsi(io.TextIOWrapper): - def __init__(self, stream: t.IO[bytes], *, color: bool, **kwargs: t.Any): - super().__init__(stream, **kwargs) - self.color = color - - def write(self, text: str) -> int: - if not self.color: - text = strip_ansi(text) - return super().write(text) - - -def _pager_contextmanager( - color: bool | None = None, -) -> t.ContextManager[tuple[t.BinaryIO | t.TextIO, str, bool]]: - """Decide what method to use for paging through text.""" - stdout = _default_text_stdout() - - # There are no standard streams attached to write to. For example, - # pythonw on Windows. - if stdout is None: - stdout = StringIO() - - if not isatty(sys.stdin) or not isatty(stdout): - return _nullpager(stdout, color) - - # Split using POSIX mode (the default) so that quote characters are - # stripped from tokens and quoted Windows paths are preserved. - # Non-POSIX mode retains quotes in tokens, and wrapping tokens - # with shlex.quote re-introduces quoting issues on Windows. - pager_cmd_parts = shlex.split(os.environ.get("PAGER", "")) - if pager_cmd_parts: - if WIN: - return _tempfilepager(pager_cmd_parts, color) - return _pipepager(pager_cmd_parts, color) - - if os.environ.get("TERM") in ("dumb", "emacs"): - return _nullpager(stdout, color) - if WIN or sys.platform.startswith("os2"): - return _tempfilepager(["more"], color) - return _pipepager(["less"], color) - - -@contextlib.contextmanager -def get_pager_file(color: bool | None = None) -> t.Generator[t.TextIO, None, None]: - """Context manager. - Yields a writable file-like object which can be used as an output pager. - .. versionadded:: 8.4 - :param color: controls if the pager supports ANSI colors or not. The - default is autodetection. - """ - with _pager_contextmanager(color=color) as (stream, encoding, color): - # Split streams by capabilities rather than the abstract TextIO / - # BinaryIO annotations: buffered text streams can be unwrapped to bytes, - # while text-only streams are yielded as-is. - if _has_binary_buffer(stream): - # Text stream backed by a binary buffer. - stream = MaybeStripAnsi(stream.buffer, color=color, encoding=encoding) - elif isinstance(stream, t.BinaryIO): - # Binary stream - stream = MaybeStripAnsi(stream, color=color, encoding=encoding) - try: - yield stream - finally: - stream.flush() - - -@contextlib.contextmanager -def _pipepager( - cmd_parts: list[str], color: bool | None = None -) -> t.Iterator[tuple[t.BinaryIO | t.TextIO, str, bool]]: - """Page through text by feeding it to another program. - - Invokes the pager via :class:`subprocess.Popen` with an ``argv`` list - produced by :func:`shlex.split`. The command is resolved to an absolute - path with :func:`shutil.which` as recommended by the - :mod:`subprocess` docs for Windows compatibility. - - Invoking a pager through this might support colors: if piping to - ``less`` and the user hasn't decided on colors, ``LESS=-R`` is set - automatically. - """ - # Split the command into the invoked CLI and its parameters. - if not cmd_parts: - stdout = _default_text_stdout() or StringIO() - yield stdout, "utf-8", False - return - - import shutil - - cmd = cmd_parts[0] - cmd_params = cmd_parts[1:] - - cmd_filepath = shutil.which(cmd) - if not cmd_filepath: - stdout = _default_text_stdout() or StringIO() - yield stdout, "utf-8", False - return - - # Produces a normalized absolute path string. - # multi-call binaries such as busybox derive their identity from the symlink - # less -> busybox. resolve() causes them to misbehave. (eg. less becomes busybox) - cmd_path = Path(cmd_filepath).absolute() - cmd_name = cmd_path.name - - import subprocess - - # Make a local copy of the environment to not affect the global one. - env = dict(os.environ) - - # If we're piping to less and the user hasn't decided on colors, we enable - # them by default we find the -R flag in the command line arguments. - if color is None and cmd_name == "less": - less_flags = f"{os.environ.get('LESS', '')}{' '.join(cmd_params)}" - if not less_flags: - env["LESS"] = "-R" - color = True - elif "r" in less_flags or "R" in less_flags: - color = True - - if color is None: - color = False - - c = subprocess.Popen( - [str(cmd_path)] + cmd_params, - shell=False, - stdin=subprocess.PIPE, - env=env, - errors="replace", - text=True, - ) - stdin = t.cast(t.BinaryIO, c.stdin) - encoding = get_best_encoding(stdin) - try: - yield stdin, encoding, color - except BrokenPipeError: - # In case the pager exited unexpectedly, ignore the broken pipe error. - pass - except Exception as e: - # In case there is an exception we want to close the pager immediately - # and let the caller handle it. - # Otherwise the pager will keep running, and the user may not notice - # the error message, or worse yet it may leave the terminal in a broken state. - c.terminate() - raise e - finally: - # We must close stdin and wait for the pager to exit before we continue - try: - stdin.close() - # Close implies flush, so it might throw a BrokenPipeError if the pager - # process exited already. - except BrokenPipeError: - pass - - # Less doesn't respect ^C, but catches it for its own UI purposes (aborting - # search or other commands inside less). - # - # That means when the user hits ^C, the parent process (click) terminates, - # but less is still alive, paging the output and messing up the terminal. - # - # If the user wants to make the pager exit on ^C, they should set - # `LESS='-K'`. It's not our decision to make. - while True: - try: - c.wait() - except KeyboardInterrupt: - pass - else: - break - - -@contextlib.contextmanager -def _tempfilepager( - cmd_parts: list[str], color: bool | None = None -) -> t.Iterator[tuple[t.BinaryIO | t.TextIO, str, bool]]: - """Page through text by invoking a program on a temporary file. - - Used as the primary pager strategy on Windows (where piping to - ``more`` adds spurious ``\\r\\n``), and as a fallback on other - platforms. The command is resolved to an absolute path with - :func:`shutil.which`. - """ - # Split the command into the invoked CLI and its parameters. - if not cmd_parts: - stdout = _default_text_stdout() or StringIO() - yield stdout, "utf-8", False - return - - import shutil - import subprocess - - cmd = cmd_parts[0] - - cmd_filepath = shutil.which(cmd) - if not cmd_filepath: - stdout = _default_text_stdout() or StringIO() - yield stdout, "utf-8", False - return - - # Produces a normalized absolute path string. - # multi-call binaries such as busybox derive their identity from the symlink - # less -> busybox. resolve() causes them to misbehave. (eg. less becomes busybox) - cmd_path = Path(cmd_filepath).absolute() - - import tempfile - - encoding = get_best_encoding(sys.stdout) - if color is None: - color = False - # On Windows, NamedTemporaryFile cannot be opened by another process - # while Python still has it open, so we use delete=False and clean up manually - # rather than using a contextmanager here. - f = tempfile.NamedTemporaryFile(mode="wb", delete=False) - try: - yield t.cast(t.BinaryIO, f), encoding, color - f.flush() - f.close() - subprocess.call([str(cmd_path), f.name]) - finally: - os.unlink(f.name) - - -class _SkipClose: - def __init__(self, stream: t.IO[t.Any]) -> None: - self.stream = stream - - def __getattr__(self, name: str) -> t.Any: - return getattr(self.stream, name) - - @property - def buffer(self) -> t.BinaryIO: - return _SkipClose(self.stream.buffer) # type: ignore[attr-defined, return-value] - - def close(self) -> None: - pass - - -@contextlib.contextmanager -def _nullpager( - stream: t.TextIO, color: bool | None = None -) -> t.Iterator[tuple[t.TextIO, str, bool]]: - """Simply print unformatted text. This is the ultimate fallback. Don't close the - output stream in this case, since it's coming from elsewhere rather than our - internal helpers. - """ - encoding = get_best_encoding(stream) - - if color is None: - color = False - - yield _SkipClose(stream), encoding, color # type: ignore[misc] - - -class Editor: - def __init__( - self, - editor: str | None = None, - env: cabc.Mapping[str, str] | None = None, - require_save: bool = True, - extension: str = ".txt", - ) -> None: - self.editor = editor - self.env = env - self.require_save = require_save - self.extension = extension - - def get_editor(self) -> str: - if self.editor is not None: - return self.editor - for key in "VISUAL", "EDITOR": - rv = os.environ.get(key) - if rv: - return rv - if WIN: - return "notepad" - - from shutil import which - - for editor in "sensible-editor", "vim", "nano": - if which(editor) is not None: - return editor - return "vi" - - def edit_files(self, filenames: cabc.Iterable[str]) -> None: - """Open files in the user's editor.""" - import shlex - import subprocess - - editor = self.get_editor() - environ: dict[str, str] | None = None - - if self.env: - environ = os.environ.copy() - environ.update(self.env) - - try: - # Split in POSIX mode (the default) for the same reasons as - # in pager(): strips quotes from tokens and preserves quoted - # Windows paths. - c = subprocess.Popen( - args=shlex.split(editor) + list(filenames), - env=environ, - ) - exit_code = c.wait() - if exit_code != 0: - raise ClickException( - _("{editor}: Editing failed").format(editor=editor) - ) - except OSError as e: - raise ClickException( - _("{editor}: Editing failed: {e}").format(editor=editor, e=e) - ) from e - - @t.overload - def edit(self, text: bytes | bytearray) -> bytes | None: ... - - # We cannot know whether or not the type expected is str or bytes when None - # is passed, so str is returned as that was what was done before. - @t.overload - def edit(self, text: str | None) -> str | None: ... - - def edit(self, text: str | bytes | bytearray | None) -> str | bytes | None: - import tempfile - - if text is None: - data: bytes | bytearray = b"" - elif isinstance(text, (bytes, bytearray)): - data = text - else: - if text and not text.endswith("\n"): - text += "\n" - - if WIN: - data = text.replace("\n", "\r\n").encode("utf-8-sig") - else: - data = text.encode("utf-8") - - fd, name = tempfile.mkstemp(prefix="editor-", suffix=self.extension) - f: t.BinaryIO - - try: - with os.fdopen(fd, "wb") as f: - f.write(data) - - # If the filesystem resolution is 1 second, like Mac OS - # 10.12 Extended, or 2 seconds, like FAT32, and the editor - # closes very fast, require_save can fail. Set the modified - # time to be 2 seconds in the past to work around this. - os.utime(name, (os.path.getatime(name), os.path.getmtime(name) - 2)) - # Depending on the resolution, the exact value might not be - # recorded, so get the new recorded value. - timestamp = os.path.getmtime(name) - - self.edit_files((name,)) - - if self.require_save and os.path.getmtime(name) == timestamp: - return None - - with open(name, "rb") as f: - rv = f.read() - - if isinstance(text, (bytes, bytearray)): - return rv - - return rv.decode("utf-8-sig").replace("\r\n", "\n") - finally: - os.unlink(name) - - -def open_url(url: str, wait: bool = False, locate: bool = False) -> int: - import subprocess - - def _unquote_file(url: str) -> str: - from urllib.parse import unquote - - if url.startswith("file://"): - url = unquote(url[7:]) - - return url - - if sys.platform == "darwin": - args = ["open"] - if wait: - args.append("-W") - if locate: - args.append("-R") - args.append(_unquote_file(url)) - null = open("/dev/null", "w") - try: - return subprocess.Popen(args, stderr=null).wait() - finally: - null.close() - elif WIN: - if locate: - url = _unquote_file(url) - args = ["explorer", "/select,", url] - try: - return subprocess.call(args) - except OSError: - return 127 - else: - try: - os.startfile(url) # type: ignore[attr-defined] - except OSError: - return 127 - return 0 - elif CYGWIN: - if locate: - url = _unquote_file(url) - args = ["cygstart", os.path.dirname(url)] - else: - args = ["cygstart"] - if wait: - args.append("-w") - args.append(url) - try: - return subprocess.call(args) - except OSError: - # Command not found - return 127 - - try: - if locate: - url = os.path.dirname(_unquote_file(url)) or "." - else: - url = _unquote_file(url) - c = subprocess.Popen(["xdg-open", url]) - if wait: - return c.wait() - return 0 - except OSError: - if url.startswith(("http://", "https://")) and not locate and not wait: - import webbrowser - - webbrowser.open(url) - return 0 - return 1 - - -def _translate_ch_to_exc(ch: str) -> None: - if ch == "\x03": - raise KeyboardInterrupt() - - if ch == "\x04" and not WIN: # Unix-like, Ctrl+D - raise EOFError() - - if ch == "\x1a" and WIN: # Windows, Ctrl+Z - raise EOFError() - - -if sys.platform == "win32": - import msvcrt - - @contextlib.contextmanager - def raw_terminal() -> cabc.Iterator[int]: - yield -1 - - def getchar(echo: bool) -> str: - # The function `getch` will return a bytes object corresponding to - # the pressed character. Since Windows 10 build 1803, it will also - # return \x00 when called a second time after pressing a regular key. - # - # `getwch` does not share this probably-bugged behavior. Moreover, it - # returns a Unicode object by default, which is what we want. - # - # Either of these functions will return \x00 or \xe0 to indicate - # a special key, and you need to call the same function again to get - # the "rest" of the code. The fun part is that \u00e0 is - # "latin small letter a with grave", so if you type that on a French - # keyboard, you _also_ get a \xe0. - # E.g., consider the Up arrow. This returns \xe0 and then \x48. The - # resulting Unicode string reads as "a with grave" + "capital H". - # This is indistinguishable from when the user actually types - # "a with grave" and then "capital H". - # - # When \xe0 is returned, we assume it's part of a special-key sequence - # and call `getwch` again, but that means that when the user types - # the \u00e0 character, `getchar` doesn't return until a second - # character is typed. - # The alternative is returning immediately, but that would mess up - # cross-platform handling of arrow keys and others that start with - # \xe0. Another option is using `getch`, but then we can't reliably - # read non-ASCII characters, because return values of `getch` are - # limited to the current 8-bit codepage. - # - # Anyway, Click doesn't claim to do this Right(tm), and using `getwch` - # is doing the right thing in more situations than with `getch`. - - if echo: - func = t.cast(t.Callable[[], str], msvcrt.getwche) - else: - func = t.cast(t.Callable[[], str], msvcrt.getwch) - - rv = func() - - if rv in ("\x00", "\xe0"): - # \x00 and \xe0 are control characters that indicate special key, - # see above. - rv += func() - - _translate_ch_to_exc(rv) - return rv - -else: - import termios - import tty - - @contextlib.contextmanager - def raw_terminal() -> cabc.Iterator[int]: - f: t.TextIO | None - fd: int - - if not isatty(sys.stdin): - f = open("/dev/tty") - fd = f.fileno() - else: - fd = sys.stdin.fileno() - f = None - - try: - old_settings = termios.tcgetattr(fd) - - try: - tty.setraw(fd) - yield fd - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - sys.stdout.flush() - - if f is not None: - f.close() - except termios.error: - pass - - def getchar(echo: bool) -> str: - with raw_terminal() as fd: - ch = os.read(fd, 32).decode(get_best_encoding(sys.stdin), "replace") - - if echo and isatty(sys.stdout): - sys.stdout.write(ch) - - _translate_ch_to_exc(ch) - return ch diff --git a/server/venv/Lib/site-packages/click/_textwrap.py b/server/venv/Lib/site-packages/click/_textwrap.py deleted file mode 100644 index 82840f2..0000000 --- a/server/venv/Lib/site-packages/click/_textwrap.py +++ /dev/null @@ -1,188 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import textwrap -from contextlib import contextmanager - -from ._compat import _ansi_re -from ._compat import term_len - - -def _truncate_visible(text: str, n: int) -> str: - """Return the longest prefix of ``text`` containing at most ``n`` visible - characters. - - ANSI escape sequences inside the prefix are kept intact and do not count - toward the visible width. A cut is never placed inside an escape sequence. - """ - if n <= 0: - return "" - - visible = 0 - i = 0 - cut = 0 - end = len(text) - while i < end: - m = _ansi_re.match(text, i) - if m is not None: - i = m.end() - continue - visible += 1 - i += 1 - cut = i - if visible >= n: - break - return text[:cut] - - -class TextWrapper(textwrap.TextWrapper): - """``textwrap.TextWrapper`` variant that measures widths by visible - character count. - - ANSI escape sequences embedded in chunks, indents, or the placeholder are - excluded from the width budget. Without this, styled help text (a styled - ``Usage:`` prefix, a colorized option name, ...) would be wrapped earlier - than its visible length warrants and tokens would split mid-word. - """ - - def _handle_long_word( - self, - reversed_chunks: list[str], - cur_line: list[str], - cur_len: int, - width: int, - ) -> None: - space_left = max(width - cur_len, 1) - - if self.break_long_words: - last = reversed_chunks[-1] - cut = _truncate_visible(last, space_left) - res = last[len(cut) :] - cur_line.append(cut) - reversed_chunks[-1] = res - elif not cur_line: - cur_line.append(reversed_chunks.pop()) - - def _wrap_chunks(self, chunks: list[str]) -> list[str]: - """Wrap chunks counting widths in visible characters. - - Mirrors the algorithm of :meth:`textwrap.TextWrapper._wrap_chunks` - with every width measurement routed through - :func:`click._compat.term_len` instead of :func:`len`, so ANSI escape - bytes in chunks, indents, or the placeholder do not inflate the count. - - .. seealso:: - :class:`textwrap.TextWrapper` in the Python standard library documentation: - https://docs.python.org/3/library/textwrap.html#textwrap.TextWrapper - - Reference implementation in CPython: - https://github.com/python/cpython/blob/main/Lib/textwrap.py - """ - lines: list[str] = [] - if self.width <= 0: - raise ValueError(f"invalid width {self.width!r} (must be > 0)") - if self.max_lines is not None: - if self.max_lines > 1: - indent = self.subsequent_indent - else: - indent = self.initial_indent - if term_len(indent) + term_len(self.placeholder.lstrip()) > self.width: - raise ValueError("placeholder too large for max width") - - chunks.reverse() - - while chunks: - cur_line: list[str] = [] - cur_len = 0 - - if lines: - indent = self.subsequent_indent - else: - indent = self.initial_indent - - width = self.width - term_len(indent) - - if self.drop_whitespace and chunks[-1].strip() == "" and lines: - del chunks[-1] - - while chunks: - n = term_len(chunks[-1]) - - if cur_len + n <= width: - cur_line.append(chunks.pop()) - cur_len += n - - else: - break - - if chunks and term_len(chunks[-1]) > width: - self._handle_long_word(chunks, cur_line, cur_len, width) - cur_len = sum(map(term_len, cur_line)) - - if self.drop_whitespace and cur_line and cur_line[-1].strip() == "": - cur_len -= term_len(cur_line[-1]) - del cur_line[-1] - - if cur_line: - if ( - self.max_lines is None - or len(lines) + 1 < self.max_lines - or ( - not chunks - or self.drop_whitespace - and len(chunks) == 1 - and not chunks[0].strip() - ) - and cur_len <= width - ): - lines.append(indent + "".join(cur_line)) - else: - while cur_line: - if ( - cur_line[-1].strip() - and cur_len + term_len(self.placeholder) <= width - ): - cur_line.append(self.placeholder) - lines.append(indent + "".join(cur_line)) - break - cur_len -= term_len(cur_line[-1]) - del cur_line[-1] - else: - if lines: - prev_line = lines[-1].rstrip() - if ( - term_len(prev_line) + term_len(self.placeholder) - <= self.width - ): - lines[-1] = prev_line + self.placeholder - break - lines.append(indent + self.placeholder.lstrip()) - break - - return lines - - @contextmanager - def extra_indent(self, indent: str) -> cabc.Iterator[None]: - old_initial_indent = self.initial_indent - old_subsequent_indent = self.subsequent_indent - self.initial_indent += indent - self.subsequent_indent += indent - - try: - yield - finally: - self.initial_indent = old_initial_indent - self.subsequent_indent = old_subsequent_indent - - def indent_only(self, text: str) -> str: - rv = [] - - for idx, line in enumerate(text.splitlines()): - indent = self.initial_indent - - if idx > 0: - indent = self.subsequent_indent - - rv.append(f"{indent}{line}") - - return "\n".join(rv) diff --git a/server/venv/Lib/site-packages/click/_utils.py b/server/venv/Lib/site-packages/click/_utils.py deleted file mode 100644 index 05ee2e9..0000000 --- a/server/venv/Lib/site-packages/click/_utils.py +++ /dev/null @@ -1,36 +0,0 @@ -from __future__ import annotations - -import enum -import typing as t - - -class Sentinel(enum.Enum): - """Enum used to define sentinel values. - - .. seealso:: - - `PEP 661 - Sentinel Values `_. - """ - - UNSET = object() - FLAG_NEEDS_VALUE = object() - - def __repr__(self) -> str: - return f"{self.__class__.__name__}.{self.name}" - - -UNSET: t.Literal[Sentinel.UNSET] = Sentinel.UNSET -"""Sentinel used to indicate that a value is not set.""" - -FLAG_NEEDS_VALUE: t.Literal[Sentinel.FLAG_NEEDS_VALUE] = Sentinel.FLAG_NEEDS_VALUE -"""Sentinel used to indicate 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``. -""" - -T_UNSET: t.TypeAlias = t.Literal[Sentinel.UNSET] -"""Type hint for the :data:`UNSET` sentinel value.""" - -T_FLAG_NEEDS_VALUE: t.TypeAlias = t.Literal[Sentinel.FLAG_NEEDS_VALUE] -"""Type hint for the :data:`FLAG_NEEDS_VALUE` sentinel value.""" diff --git a/server/venv/Lib/site-packages/click/_winconsole.py b/server/venv/Lib/site-packages/click/_winconsole.py deleted file mode 100644 index d25178d..0000000 --- a/server/venv/Lib/site-packages/click/_winconsole.py +++ /dev/null @@ -1,297 +0,0 @@ -# This module is based on the excellent work by Adam Bartoš who -# provided a lot of what went into the implementation here in -# the discussion to issue1602 in the Python bug tracker. -# -# There are some general differences in regards to how this works -# compared to the original patches as we do not need to patch -# the entire interpreter but just work in our little world of -# echo and prompt. -from __future__ import annotations - -import collections.abc as cabc -import io -import sys -import time -import typing as t -from ctypes import Array -from ctypes import byref -from ctypes import c_char -from ctypes import c_char_p -from ctypes import c_int -from ctypes import c_ssize_t -from ctypes import c_ulong -from ctypes import c_void_p -from ctypes import POINTER -from ctypes import py_object -from ctypes import Structure -from ctypes.wintypes import DWORD -from ctypes.wintypes import HANDLE -from ctypes.wintypes import LPCWSTR -from ctypes.wintypes import LPWSTR -from gettext import gettext as _ - -from ._compat import _NonClosingTextIOWrapper - -assert sys.platform == "win32" -import msvcrt # noqa: E402 -from ctypes import windll # noqa: E402 -from ctypes import WINFUNCTYPE # noqa: E402 - -c_ssize_p = POINTER(c_ssize_t) - -kernel32 = windll.kernel32 -GetStdHandle = kernel32.GetStdHandle -ReadConsoleW = kernel32.ReadConsoleW -WriteConsoleW = kernel32.WriteConsoleW -GetConsoleMode = kernel32.GetConsoleMode -GetLastError = kernel32.GetLastError -GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32)) -CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( - ("CommandLineToArgvW", windll.shell32) -) -LocalFree = WINFUNCTYPE(c_void_p, c_void_p)(("LocalFree", windll.kernel32)) - -STDIN_HANDLE = GetStdHandle(-10) -STDOUT_HANDLE = GetStdHandle(-11) -STDERR_HANDLE = GetStdHandle(-12) - -PyBUF_SIMPLE = 0 -PyBUF_WRITABLE = 1 - -ERROR_SUCCESS = 0 -ERROR_NOT_ENOUGH_MEMORY = 8 -ERROR_OPERATION_ABORTED = 995 - -STDIN_FILENO = 0 -STDOUT_FILENO = 1 -STDERR_FILENO = 2 - -EOF = b"\x1a" -MAX_BYTES_WRITTEN = 32767 - -if t.TYPE_CHECKING: - try: - # Using `typing_extensions.Buffer` instead of `collections.abc` - # on Windows for some reason does not have `Sized` implemented. - from collections.abc import Buffer # type: ignore - except ImportError: - from typing_extensions import Buffer - -try: - from ctypes import pythonapi -except ImportError: - # On PyPy we cannot get buffers so our ability to operate here is - # severely limited. - get_buffer = None -else: - - class Py_buffer(Structure): - _fields_ = [ # noqa: RUF012 - ("buf", c_void_p), - ("obj", py_object), - ("len", c_ssize_t), - ("itemsize", c_ssize_t), - ("readonly", c_int), - ("ndim", c_int), - ("format", c_char_p), - ("shape", c_ssize_p), - ("strides", c_ssize_p), - ("suboffsets", c_ssize_p), - ("internal", c_void_p), - ] - - PyObject_GetBuffer = pythonapi.PyObject_GetBuffer - PyBuffer_Release = pythonapi.PyBuffer_Release - - def get_buffer(obj: Buffer, writable: bool = False) -> Array[c_char]: - buf = Py_buffer() - flags: int = PyBUF_WRITABLE if writable else PyBUF_SIMPLE - PyObject_GetBuffer(py_object(obj), byref(buf), flags) - - try: - buffer_type = c_char * buf.len - out: Array[c_char] = buffer_type.from_address(buf.buf) - return out - finally: - PyBuffer_Release(byref(buf)) - - -class _WindowsConsoleRawIOBase(io.RawIOBase): - def __init__(self, handle: int | None) -> None: - self.handle = handle - - def isatty(self) -> t.Literal[True]: - super().isatty() - return True - - -class _WindowsConsoleReader(_WindowsConsoleRawIOBase): - def readable(self) -> t.Literal[True]: - return True - - def readinto(self, b: Buffer) -> int: - bytes_to_be_read = len(b) - if not bytes_to_be_read: - return 0 - elif bytes_to_be_read % 2: - raise ValueError( - "cannot read odd number of bytes from UTF-16-LE encoded console" - ) - - buffer = get_buffer(b, writable=True) - code_units_to_be_read = bytes_to_be_read // 2 - code_units_read = c_ulong() - - rv = ReadConsoleW( - HANDLE(self.handle), - buffer, - code_units_to_be_read, - byref(code_units_read), - None, - ) - if GetLastError() == ERROR_OPERATION_ABORTED: - # wait for KeyboardInterrupt - time.sleep(0.1) - if not rv: - raise OSError(_("Windows error: {error}").format(error=GetLastError())) - - if buffer[0] == EOF: - return 0 - return 2 * code_units_read.value - - -class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): - def writable(self) -> t.Literal[True]: - return True - - @staticmethod - def _get_error_message(errno: int) -> str: - if errno == ERROR_SUCCESS: - return "ERROR_SUCCESS" - elif errno == ERROR_NOT_ENOUGH_MEMORY: - return "ERROR_NOT_ENOUGH_MEMORY" - return _("Windows error: {error}").format(error=errno) - - def write(self, b: Buffer) -> int: - bytes_to_be_written = len(b) - buf = get_buffer(b) - code_units_to_be_written = min(bytes_to_be_written, MAX_BYTES_WRITTEN) // 2 - code_units_written = c_ulong() - - WriteConsoleW( - HANDLE(self.handle), - buf, - code_units_to_be_written, - byref(code_units_written), - None, - ) - bytes_written = 2 * code_units_written.value - - if bytes_written == 0 and bytes_to_be_written > 0: - raise OSError(self._get_error_message(GetLastError())) - return bytes_written - - -class ConsoleStream: - def __init__(self, text_stream: t.TextIO, byte_stream: t.BinaryIO) -> None: - self._text_stream = text_stream - self.buffer = byte_stream - - @property - def name(self) -> str: - return self.buffer.name - - def write(self, x: t.AnyStr) -> int: - if isinstance(x, str): - return self._text_stream.write(x) - try: - self.flush() - except Exception: - pass - return self.buffer.write(x) - - def writelines(self, lines: cabc.Iterable[t.AnyStr]) -> None: - for line in lines: - self.write(line) - - def __getattr__(self, name: str) -> t.Any: - return getattr(self._text_stream, name) - - def isatty(self) -> bool: - return self.buffer.isatty() - - def __repr__(self) -> str: - return f"" - - -def _get_text_stdin(buffer_stream: t.BinaryIO) -> t.TextIO: - text_stream = _NonClosingTextIOWrapper( - io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), - "utf-16-le", - "strict", - line_buffering=True, - ) - return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) - - -def _get_text_stdout(buffer_stream: t.BinaryIO) -> t.TextIO: - text_stream = _NonClosingTextIOWrapper( - io.BufferedWriter(_WindowsConsoleWriter(STDOUT_HANDLE)), - "utf-16-le", - "strict", - line_buffering=True, - ) - return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) - - -def _get_text_stderr(buffer_stream: t.BinaryIO) -> t.TextIO: - text_stream = _NonClosingTextIOWrapper( - io.BufferedWriter(_WindowsConsoleWriter(STDERR_HANDLE)), - "utf-16-le", - "strict", - line_buffering=True, - ) - return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) - - -_stream_factories: cabc.Mapping[int, t.Callable[[t.BinaryIO], t.TextIO]] = { - 0: _get_text_stdin, - 1: _get_text_stdout, - 2: _get_text_stderr, -} - - -def _is_console(f: t.TextIO) -> bool: - if not hasattr(f, "fileno"): - return False - - try: - fileno = f.fileno() - except (OSError, io.UnsupportedOperation): - return False - - handle = msvcrt.get_osfhandle(fileno) - return bool(GetConsoleMode(handle, byref(DWORD()))) - - -def _get_windows_console_stream( - f: t.TextIO, encoding: str | None, errors: str | None -) -> t.TextIO | None: - if ( - get_buffer is None - or encoding not in {"utf-16-le", None} - or errors not in {"strict", None} - or not _is_console(f) - ): - return None - - func = _stream_factories.get(f.fileno()) - if func is None: - return None - - b = getattr(f, "buffer", None) - - if b is None: - return None - - return func(b) diff --git a/server/venv/Lib/site-packages/click/core.py b/server/venv/Lib/site-packages/click/core.py deleted file mode 100644 index bc04f64..0000000 --- a/server/venv/Lib/site-packages/click/core.py +++ /dev/null @@ -1,3542 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import enum -import errno -import inspect -import os -import sys -import typing as t -from abc import ABC -from abc import abstractmethod -from collections import abc -from collections import Counter -from contextlib import AbstractContextManager -from contextlib import contextmanager -from contextlib import ExitStack -from functools import update_wrapper -from gettext import gettext as _ -from gettext import ngettext -from itertools import repeat -from types import TracebackType - -from . import types -from ._utils import FLAG_NEEDS_VALUE -from ._utils import UNSET -from .exceptions import Abort -from .exceptions import BadParameter -from .exceptions import ClickException -from .exceptions import Exit -from .exceptions import MissingParameter -from .exceptions import NoArgsIsHelpError -from .exceptions import NoSuchCommand -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 _OptionParser -from .parser import _split_opt -from .termui import confirm -from .termui import prompt -from .termui import style -from .utils import _detect_program_name -from .utils import _expand_args -from .utils import echo -from .utils import make_default_short_help -from .utils import make_str -from .utils import PacifyFlushWrapper - -if t.TYPE_CHECKING: - from .shell_completion import CompletionItem - -F = t.TypeVar("F", bound="t.Callable[..., t.Any]") -V = t.TypeVar("V") - - -def _complete_visible_commands( - ctx: Context, incomplete: str -) -> cabc.Iterator[tuple[str, Command]]: - """List all the subcommands of a group that start with the - incomplete value and aren't hidden. - - :param ctx: Invocation context for the group. - :param incomplete: Value being completed. May be empty. - """ - multi = t.cast(Group, ctx.command) - - for name in multi.list_commands(ctx): - if name.startswith(incomplete): - command = multi.get_command(ctx, name) - - if command is not None and not command.hidden: - yield name, command - - -def _check_nested_chain( - base_command: Group, cmd_name: str, cmd: Command, register: bool = False -) -> None: - if not base_command.chain or not isinstance(cmd, Group): - return - - if register: - message = ( - f"It is not possible to add the group {cmd_name!r} to another" - f" group {base_command.name!r} that is in chain mode." - ) - else: - message = ( - f"Found the group {cmd_name!r} as subcommand to another group " - f" {base_command.name!r} that is in chain mode. This is not supported." - ) - - raise RuntimeError(message) - - -def _format_deprecated_label(deprecated: bool | str) -> str: - """Return the parenthesized deprecation label shown in help text.""" - label = _("deprecated").upper() - if isinstance(deprecated, str): - return f"({label}: {deprecated})" - return f"({label})" - - -def _format_deprecated_suffix(deprecated: bool | str) -> str: - """Return the trailing reason for a ``DeprecationWarning`` message, - prefixed with a space, or an empty string when no reason was given. - """ - if isinstance(deprecated, str): - return f" {deprecated}" - return "" - - -def batch(iterable: cabc.Iterable[V], batch_size: int) -> list[tuple[V, ...]]: - return list(zip(*repeat(iter(iterable), batch_size), strict=False)) - - -@contextmanager -def augment_usage_errors( - ctx: Context, param: Parameter | None = None -) -> cabc.Iterator[None]: - """Context manager that attaches extra information to exceptions.""" - try: - yield - except BadParameter as e: - if e.ctx is None: - e.ctx = ctx - if param is not None and e.param is None: - e.param = param - raise - except UsageError as e: - if e.ctx is None: - e.ctx = ctx - raise - - -def iter_params_for_processing( - invocation_order: cabc.Sequence[Parameter], - declaration_order: cabc.Sequence[Parameter], -) -> list[Parameter]: - """Returns all declared parameters in the order they should be processed. - - The declared parameters are re-shuffled depending on the order in which - they were invoked, as well as the eagerness of each parameters. - - The invocation order takes precedence over the declaration order. I.e. the - order in which the user provided them to the CLI is respected. - - This behavior and its effect on callback evaluation is detailed at: - https://click.palletsprojects.com/en/stable/advanced/#callback-evaluation-order - """ - - def sort_key(item: Parameter) -> tuple[bool, float]: - try: - idx: float = invocation_order.index(item) - except ValueError: - idx = float("inf") - - return not item.is_eager, idx - - return sorted(declaration_order, key=sort_key) - - -class ParameterSource(enum.IntEnum): - """This is an :class:`~enum.IntEnum` 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. - - Members are ordered from most explicit to least explicit source. - This allows comparison to check if a value was explicitly provided: - - .. code-block:: python - - source = ctx.get_parameter_source("port") - if source < click.ParameterSource.DEFAULT_MAP: - ... # value was explicitly set - - .. versionchanged:: 8.3.3 - Use :class:`~enum.IntEnum` and reorder members from most to - least explicit. Supports comparison operators. - - .. versionchanged:: 8.0 - Use :class:`~enum.Enum` and drop the ``validate`` method. - - .. versionchanged:: 8.0 - Added the ``PROMPT`` value. - """ - - PROMPT = enum.auto() - """Used a prompt to confirm a default or provide a 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_MAP = enum.auto() - """Used a default provided by :attr:`Context.default_map`.""" - DEFAULT = enum.auto() - """Used the default specified by the parameter.""" - - -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 that it's - the name of the script. - :param obj: an arbitrary object of user data. - :param auto_envvar_prefix: the prefix to use for automatic environment - variables. If this is `None` then reading - from environment variables is disabled. This - does not affect manually set environment - variables which are always read. - :param default_map: a dictionary (like object) with default values - for parameters. - :param terminal_width: the width of the terminal. The default is - inherit from parent context. If no context - defines the terminal width then auto - detection will be applied. - :param max_content_width: the maximum width for content rendered by - Click (this currently only affects help - pages). This defaults to 80 characters if - not overridden. In other words: even if the - terminal is larger than that, Click will not - format things wider than 80 characters by - default. In addition to that, formatters might - add some safety mapping on the right. - :param resilient_parsing: if this flag is enabled then Click will - parse without any interactivity or callback - invocation. Default values will also be - ignored. This is useful for implementing - things such as completion support. - :param allow_extra_args: if this is set to `True` then extra arguments - at the end will not raise an error and will be - kept on the context. The default is to inherit - from the command. - :param allow_interspersed_args: if this is set to `False` then options - and arguments cannot be mixed. The - default is to inherit from the command. - :param ignore_unknown_options: instructs click to ignore options it does - not know and keeps them for later - processing. - :param help_option_names: optionally a list of strings that define how - the default help parameter is named. The - default is ``['--help']``. - :param token_normalize_func: an optional function that is used to - normalize tokens (options, choices, - etc.). This for instance can be used to - implement case insensitive behavior. - :param color: controls if the terminal supports ANSI colors or not. The - default is autodetection. This is only needed if ANSI - codes are used in texts that Click prints which is by - default not the case. This for instance would affect - help output. - :param show_default: Show the default value for commands. If this - value is not set, it defaults to the value from the parent - context. ``Command.show_default`` overrides this default for the - specific command. - - .. versionchanged:: 8.2 - The ``protected_args`` attribute is deprecated and will be removed in - Click 9.0. ``args`` will contain remaining unparsed tokens. - - .. versionchanged:: 8.1 - The ``show_default`` parameter is overridden by - ``Command.show_default``, instead of the other way around. - - .. versionchanged:: 8.0 - The ``show_default`` parameter defaults to the value from the - parent context. - - .. versionchanged:: 7.1 - Added the ``show_default`` parameter. - - .. versionchanged:: 4.0 - Added the ``color``, ``ignore_unknown_options``, and - ``max_content_width`` parameters. - - .. versionchanged:: 3.0 - Added the ``allow_extra_args`` and ``allow_interspersed_args`` - parameters. - - .. versionchanged:: 2.0 - Added the ``resilient_parsing``, ``help_option_names``, and - ``token_normalize_func`` parameters. - """ - - #: The formatter class to create with :meth:`make_formatter`. - #: - #: .. versionadded:: 8.0 - formatter_class: type[HelpFormatter] = HelpFormatter - - def __init__( - self, - command: Command, - parent: Context | None = None, - info_name: str | None = None, - obj: t.Any | None = None, - auto_envvar_prefix: str | None = None, - default_map: cabc.MutableMapping[str, t.Any] | None = None, - terminal_width: int | None = None, - max_content_width: int | None = None, - resilient_parsing: bool = False, - allow_extra_args: bool | None = None, - allow_interspersed_args: bool | None = None, - ignore_unknown_options: bool | None = None, - help_option_names: list[str] | None = None, - token_normalize_func: t.Callable[[str], str] | None = None, - color: bool | None = None, - show_default: bool | None = None, - ) -> None: - #: the parent context or `None` if none exists. - self.parent = parent - #: the :class:`Command` for this context. - self.command = command - #: the descriptive information name - self.info_name = info_name - #: Map of parameter names to their parsed values. Parameters - #: with ``expose_value=False`` are not stored. - self.params: dict[str, t.Any] = {} - #: the leftover arguments. - self.args: list[str] = [] - #: protected arguments. These are arguments that are prepended - #: to `args` when certain parsing scenarios are encountered but - #: must be never propagated to another arguments. This is used - #: to implement nested parsing. - self._protected_args: list[str] = [] - #: the collected prefixes of the command's options. - self._opt_prefixes: set[str] = set(parent._opt_prefixes) if parent else set() - - if obj is None and parent is not None: - obj = parent.obj - - #: the user object stored. - self.obj: t.Any = obj - self._meta: dict[str, t.Any] = getattr(parent, "meta", {}) - - #: A dictionary (-like object) with defaults for parameters. - if ( - default_map is None - and info_name is not None - and parent is not None - and parent.default_map is not None - ): - default_map = parent.default_map.get(info_name) - - self.default_map: cabc.MutableMapping[str, t.Any] | None = default_map - - #: This flag indicates if a subcommand is going to be executed. A - #: group callback can use this information to figure out if it's - #: being executed directly or because the execution flow passes - #: onwards to a subcommand. By default it's None, but it can be - #: the name of the subcommand to execute. - #: - #: If chaining is enabled this will be set to ``'*'`` in case - #: any commands are executed. It is however not possible to - #: figure out which ones. If you require this knowledge you - #: should use a :func:`result_callback`. - self.invoked_subcommand: str | None = None - - if terminal_width is None and parent is not None: - terminal_width = parent.terminal_width - - #: The width of the terminal (None is autodetection). - self.terminal_width: int | None = terminal_width - - if max_content_width is None and parent is not None: - max_content_width = parent.max_content_width - - #: The maximum width of formatted content (None implies a sensible - #: default which is 80 for most things). - self.max_content_width: int | None = max_content_width - - if allow_extra_args is None: - allow_extra_args = command.allow_extra_args - - #: Indicates if the context allows extra args or if it should - #: fail on parsing. - #: - #: .. versionadded:: 3.0 - self.allow_extra_args = allow_extra_args - - if allow_interspersed_args is None: - allow_interspersed_args = command.allow_interspersed_args - - #: Indicates if the context allows mixing of arguments and - #: options or not. - #: - #: .. versionadded:: 3.0 - self.allow_interspersed_args: bool = allow_interspersed_args - - if ignore_unknown_options is None: - ignore_unknown_options = command.ignore_unknown_options - - #: Instructs click to ignore options that a command does not - #: understand and will store it on the context for later - #: processing. This is primarily useful for situations where you - #: want to call into external programs. Generally this pattern is - #: strongly discouraged because it's not possibly to losslessly - #: forward all arguments. - #: - #: .. versionadded:: 4.0 - self.ignore_unknown_options: bool = ignore_unknown_options - - if help_option_names is None: - if parent is not None: - help_option_names = parent.help_option_names - else: - help_option_names = ["--help"] - - #: The names for the help options. - self.help_option_names: list[str] = help_option_names - - if token_normalize_func is None and parent is not None: - token_normalize_func = parent.token_normalize_func - - #: An optional normalization function for tokens. This is - #: options, choices, commands etc. - self.token_normalize_func: t.Callable[[str], str] | None = token_normalize_func - - #: Indicates if resilient parsing is enabled. In that case Click - #: will do its best to not cause any failures and default values - #: will be ignored. Useful for completion. - self.resilient_parsing: bool = resilient_parsing - - # If there is no envvar prefix yet, but the parent has one and - # the command on this level has a name, we can expand the envvar - # prefix automatically. - if auto_envvar_prefix is None: - if ( - parent is not None - and parent.auto_envvar_prefix is not None - and self.info_name is not None - ): - auto_envvar_prefix = ( - f"{parent.auto_envvar_prefix}_{self.info_name.upper()}" - ) - else: - auto_envvar_prefix = auto_envvar_prefix.upper() - - if auto_envvar_prefix is not None: - auto_envvar_prefix = auto_envvar_prefix.replace("-", "_") - - self.auto_envvar_prefix: str | None = auto_envvar_prefix - - if color is None and parent is not None: - color = parent.color - - #: Controls if styling output is wanted or not. - self.color: bool | None = color - - if show_default is None and parent is not None: - show_default = parent.show_default - - #: Show option default values when formatting help text. - self.show_default: bool | None = show_default - - self._close_callbacks: list[t.Callable[[], t.Any]] = [] - self._depth = 0 - self._parameter_source: dict[str, ParameterSource] = {} - # Tracks whether the option that currently owns each parameter slot in - # :attr:`params` had its ``default`` set explicitly by the user. Used - # to tie-break feature-switch groups where multiple options share a - # parameter name and both fall back to their default value. - # Refs: https://github.com/pallets/click/issues/3403 - self._param_default_explicit: dict[str, bool] = {} - self._exit_stack = ExitStack() - - @property - def protected_args(self) -> list[str]: - import warnings - - warnings.warn( - "'protected_args' is deprecated and will be removed in Click 9.0." - " 'args' will contain remaining unparsed tokens.", - DeprecationWarning, - stacklevel=2, - ) - return self._protected_args - - def to_info_dict(self) -> dict[str, t.Any]: - """Gather information that could be useful for a tool generating - user-facing documentation. This traverses the entire CLI - structure. - - .. code-block:: python - - with Context(cli) as ctx: - info = ctx.to_info_dict() - - .. versionadded:: 8.0 - """ - return { - "command": self.command.to_info_dict(self), - "info_name": self.info_name, - "allow_extra_args": self.allow_extra_args, - "allow_interspersed_args": self.allow_interspersed_args, - "ignore_unknown_options": self.ignore_unknown_options, - "auto_envvar_prefix": self.auto_envvar_prefix, - } - - def __enter__(self) -> Context: - self._depth += 1 - push_context(self) - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - tb: TracebackType | None, - ) -> bool | None: - self._depth -= 1 - exit_result: bool | None = None - if self._depth == 0: - exit_result = self._close_with_exception_info(exc_type, exc_value, tb) - pop_context() - - return exit_result - - @contextmanager - def scope(self, cleanup: bool = True) -> cabc.Iterator[Context]: - """This helper method can be used with the context object to promote - it to the current thread local (see :func:`get_current_context`). - The default behavior of this is to invoke the cleanup functions which - can be disabled by setting `cleanup` to `False`. The cleanup - functions are typically used for things such as closing file handles. - - If the cleanup is intended the context object can also be directly - used as a context manager. - - Example usage:: - - with ctx.scope(): - assert get_current_context() is ctx - - This is equivalent:: - - with ctx: - assert get_current_context() is ctx - - .. versionadded:: 5.0 - - :param cleanup: controls if the cleanup functions should be run or - not. The default is to run these functions. In - some situations the context only wants to be - temporarily pushed in which case this can be disabled. - Nested pushes automatically defer the cleanup. - """ - if not cleanup: - self._depth += 1 - try: - with self as rv: - yield rv - finally: - if not cleanup: - self._depth -= 1 - - @property - def meta(self) -> dict[str, t.Any]: - """This is a dictionary which is shared with all the contexts - that are nested. It exists so that click utilities can store some - state here if they need to. It is however the responsibility of - that code to manage this dictionary well. - - The keys are supposed to be unique dotted strings. For instance - module paths are a good choice for it. What is stored in there is - irrelevant for the operation of click. However what is important is - that code that places data here adheres to the general semantics of - the system. - - Example usage:: - - LANG_KEY = f'{__name__}.lang' - - def set_language(value): - ctx = get_current_context() - ctx.meta[LANG_KEY] = value - - def get_language(): - return get_current_context().meta.get(LANG_KEY, 'en_US') - - .. versionadded:: 5.0 - """ - return self._meta - - def make_formatter(self) -> HelpFormatter: - """Creates the :class:`~click.HelpFormatter` for the help and - usage output. - - To quickly customize the formatter class used without overriding - this method, set the :attr:`formatter_class` attribute. - - .. versionchanged:: 8.0 - Added the :attr:`formatter_class` attribute. - """ - return self.formatter_class( - width=self.terminal_width, max_width=self.max_content_width - ) - - def with_resource(self, context_manager: AbstractContextManager[V]) -> V: - """Register a resource as if it were used in a ``with`` - statement. The resource will be cleaned up when the context is - popped. - - Uses :meth:`contextlib.ExitStack.enter_context`. It calls the - resource's ``__enter__()`` method and returns the result. When - the context is popped, it closes the stack, which calls the - resource's ``__exit__()`` method. - - To register a cleanup function for something that isn't a - context manager, use :meth:`call_on_close`. Or use something - from :mod:`contextlib` to turn it into a context manager first. - - .. code-block:: python - - @click.group() - @click.option("--name") - @click.pass_context - def cli(ctx): - ctx.obj = ctx.with_resource(connect_db(name)) - - :param context_manager: The context manager to enter. - :return: Whatever ``context_manager.__enter__()`` returns. - - .. versionadded:: 8.0 - """ - return self._exit_stack.enter_context(context_manager) - - def call_on_close(self, f: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]: - """Register a function to be called when the context tears down. - - This can be used to close resources opened during the script - execution. Resources that support Python's context manager - protocol which would be used in a ``with`` statement should be - registered with :meth:`with_resource` instead. - - :param f: The function to execute on teardown. - """ - return self._exit_stack.callback(f) - - def close(self) -> None: - """Invoke all close callbacks registered with - :meth:`call_on_close`, and exit all context managers entered - with :meth:`with_resource`. - """ - self._close_with_exception_info(None, None, None) - - def _close_with_exception_info( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - tb: TracebackType | None, - ) -> bool | None: - """Unwind the exit stack by calling its :meth:`__exit__` providing the exception - information to allow for exception handling by the various resources registered - using :meth;`with_resource` - - :return: Whatever ``exit_stack.__exit__()`` returns. - """ - exit_result = self._exit_stack.__exit__(exc_type, exc_value, tb) - # In case the context is reused, create a new exit stack. - self._exit_stack = ExitStack() - - return exit_result - - @property - def command_path(self) -> str: - """The computed command path. This is used for the ``usage`` - information on the help page. It's automatically created by - combining the info names of the chain of contexts to the root. - """ - rv = "" - if self.info_name is not None: - rv = self.info_name - if self.parent is not None: - parent_command_path = [self.parent.command_path] - - if isinstance(self.parent.command, Command): - for param in self.parent.command.get_params(self): - parent_command_path.extend(param.get_usage_pieces(self)) - - rv = f"{' '.join(parent_command_path)} {rv}" - return rv.lstrip() - - def find_root(self) -> Context: - """Finds the outermost context.""" - node = self - while node.parent is not None: - node = node.parent - return node - - def find_object(self, object_type: type[V]) -> V | None: - """Finds the closest object of a given type.""" - node: Context | None = self - - while node is not None: - if isinstance(node.obj, object_type): - return node.obj - - node = node.parent - - return None - - def ensure_object(self, object_type: type[V]) -> V: - """Like :meth:`find_object` but sets the innermost object to a - new instance of `object_type` if it does not exist. - """ - rv = self.find_object(object_type) - if rv is None: - self.obj = rv = object_type() - return rv - - def _default_map_has(self, name: str | None) -> bool: - """Check if :attr:`default_map` contains a real value for ``name``. - - Returns ``False`` when the key is absent, the map is ``None``, - ``name`` is ``None``, or the stored value is the internal - :data:`UNSET` sentinel. - """ - return ( - name is not None - and self.default_map is not None - and name in self.default_map - and self.default_map[name] is not UNSET - ) - - @t.overload - def lookup_default( - self, name: str, call: t.Literal[True] = True - ) -> t.Any | None: ... - - @t.overload - def lookup_default( - self, name: str, call: t.Literal[False] = ... - ) -> t.Any | t.Callable[[], t.Any] | None: ... - - def lookup_default(self, name: str, call: bool = True) -> t.Any | None: - """Get the default for a parameter from :attr:`default_map`. - - :param name: Name of the parameter. - :param call: If the default is a callable, call it. Disable to - return the callable instead. - - .. versionchanged:: 8.0 - Added the ``call`` parameter. - """ - if not self._default_map_has(name): - return None - - # Assert to make the type checker happy. - assert self.default_map is not None - value = self.default_map[name] - - if call and callable(value): - return value() - - return value - - def fail(self, message: str) -> t.NoReturn: - """Aborts the execution of the program with a specific error - message. - - :param message: the error message to fail with. - """ - raise UsageError(message, self) - - def abort(self) -> t.NoReturn: - """Aborts the script.""" - raise Abort() - - def exit(self, code: int = 0) -> t.NoReturn: - """Exits the application with a given exit code. - - .. versionchanged:: 8.2 - Callbacks and context managers registered with :meth:`call_on_close` - and :meth:`with_resource` are closed before exiting. - """ - self.close() - raise Exit(code) - - def get_usage(self) -> str: - """Helper method to get formatted usage string for the current - context and command. - """ - return self.command.get_usage(self) - - def get_help(self) -> str: - """Helper method to get formatted help page for the current - context and command. - """ - return self.command.get_help(self) - - def _make_sub_context(self, command: Command) -> Context: - """Create a new context of the same type as this context, but - for a new command. - - :meta private: - """ - return type(self)(command, info_name=command.name, parent=self) - - @t.overload - def invoke( - self, callback: t.Callable[..., V], /, *args: t.Any, **kwargs: t.Any - ) -> V: ... - - @t.overload - def invoke(self, callback: Command, /, *args: t.Any, **kwargs: t.Any) -> t.Any: ... - - def invoke( - self, callback: Command | t.Callable[..., V], /, *args: t.Any, **kwargs: t.Any - ) -> t.Any | V: - """Invokes a command callback in exactly the way it expects. There - are two ways to invoke this method: - - 1. the first argument can be a callback and all other arguments and - keyword arguments are forwarded directly to the function. - 2. the first argument is a click command object. In that case all - arguments are forwarded as well but proper click parameters - (options and click arguments) must be keyword arguments and Click - will fill in defaults. - - .. versionchanged:: 8.0 - All ``kwargs`` are tracked in :attr:`params` so they will be - passed if :meth:`forward` is called at multiple levels. - - .. versionchanged:: 3.2 - A new context is created, and missing arguments use default values. - """ - if isinstance(callback, Command): - other_cmd = callback - - if other_cmd.callback is None: - raise TypeError( - "The given command does not have a callback that can be invoked." - ) - else: - callback = t.cast("t.Callable[..., V]", other_cmd.callback) - - ctx = self._make_sub_context(other_cmd) - - for param in other_cmd.params: - if param.name not in kwargs and param.expose_value: - default_value = param.get_default(ctx) - # We explicitly hide the :attr:`UNSET` value to the user, as we - # choose to make it an implementation detail. And because ``invoke`` - # has been designed as part of Click public API, we return ``None`` - # instead. Refs: - # https://github.com/pallets/click/issues/3066 - # https://github.com/pallets/click/issues/3065 - # https://github.com/pallets/click/pull/3068 - if default_value is UNSET: - default_value = None - kwargs[param.name] = param.type_cast_value(ctx, default_value) - - # Track all kwargs as params, so that forward() will pass - # them on in subsequent calls. - ctx.params.update(kwargs) - else: - ctx = self - - with augment_usage_errors(self): - with ctx: - return callback(*args, **kwargs) - - def forward(self, cmd: Command, /, *args: t.Any, **kwargs: t.Any) -> t.Any: - """Similar to :meth:`invoke` but fills in default keyword - arguments from the current context if the other command expects - it. This cannot invoke callbacks directly, only other commands. - - .. versionchanged:: 8.0 - All ``kwargs`` are tracked in :attr:`params` so they will be - passed if ``forward`` is called at multiple levels. - """ - # Can only forward to other commands, not direct callbacks. - if not isinstance(cmd, Command): - raise TypeError("Callback is not a command.") - - for param in self.params: - if param not in kwargs: - kwargs[param] = self.params[param] - - return self.invoke(cmd, *args, **kwargs) - - def set_parameter_source(self, name: str, source: ParameterSource) -> None: - """Set the source of a parameter. This indicates the location - from which the value of the parameter was obtained. - - :param name: The name of the parameter. - :param source: A member of :class:`~click.core.ParameterSource`. - """ - self._parameter_source[name] = source - - def get_parameter_source(self, name: str) -> ParameterSource | None: - """Get the source of a parameter. This indicates the location - from which the value of the parameter was obtained. - - This can be useful for determining when a user specified a value - on the command line that is the same as the default value. It - will be :attr:`~click.core.ParameterSource.DEFAULT` only if the - value was actually taken from the default. - - :param name: The name of the parameter. - :rtype: ParameterSource - - .. versionchanged:: 8.0 - Returns ``None`` if the parameter was not provided from any - source. - """ - return self._parameter_source.get(name) - - -class Command: - """Commands are the basic building block of command line interfaces in - Click. A basic command handles command line parsing and might dispatch - more parsing to commands nested below it. - - :param name: the name of the command to use unless a group overrides it. - :param context_settings: an optional dictionary with defaults that are - passed to the context object. - :param callback: the callback to invoke. This is optional. - :param params: the parameters to register with this command. This can - be either :class:`Option` or :class:`Argument` objects. - :param help: the help string to use for this command. - :param epilog: like the help string but it's printed at the end of the - help page after everything else. - :param short_help: the short help to use for this command. This is - shown on the command listing of the parent command. - :param add_help_option: by default each command registers a ``--help`` - option. This can be disabled by this parameter. - :param no_args_is_help: this controls what happens if no arguments are - provided. This option is disabled by default. - If enabled this will add ``--help`` as argument - if no arguments are passed - :param hidden: hide this command from help outputs. - :param deprecated: If ``True`` or non-empty string, issues a message - indicating that the command is deprecated and highlights - its deprecation in --help. The message can be customized - by using a string as the value. - - .. versionchanged:: 8.2 - This is the base class for all commands, not ``BaseCommand``. - ``deprecated`` can be set to a string as well to customize the - deprecation message. - - .. versionchanged:: 8.1 - ``help``, ``epilog``, and ``short_help`` are stored unprocessed, - all formatting is done when outputting help text, not at init, - and is done even if not using the ``@command`` decorator. - - .. versionchanged:: 8.0 - Added a ``repr`` showing the command name. - - .. versionchanged:: 7.1 - Added the ``no_args_is_help`` parameter. - - .. versionchanged:: 2.0 - Added the ``context_settings`` parameter. - """ - - #: The context class to create with :meth:`make_context`. - #: - #: .. versionadded:: 8.0 - context_class: type[Context] = Context - - #: the default for the :attr:`Context.allow_extra_args` flag. - allow_extra_args = False - - #: the default for the :attr:`Context.allow_interspersed_args` flag. - allow_interspersed_args = True - - #: the default for the :attr:`Context.ignore_unknown_options` flag. - ignore_unknown_options = False - - def __init__( - self, - name: str | None, - context_settings: cabc.MutableMapping[str, t.Any] | None = None, - callback: t.Callable[..., t.Any] | None = None, - params: list[Parameter] | None = None, - help: str | None = None, - epilog: str | None = None, - short_help: str | None = None, - options_metavar: str | None = "[OPTIONS]", - add_help_option: bool = True, - no_args_is_help: bool = False, - hidden: bool = False, - deprecated: bool | str = False, - ) -> None: - #: the name the command thinks it has. Upon registering a command - #: on a :class:`Group` the group will default the command name - #: with this information. You should instead use the - #: :class:`Context`\'s :attr:`~Context.info_name` attribute. - self.name = name - - if context_settings is None: - context_settings = {} - - #: an optional dictionary with defaults passed to the context. - self.context_settings: cabc.MutableMapping[str, t.Any] = context_settings - - #: the callback to execute when the command fires. This might be - #: `None` in which case nothing happens. - self.callback = callback - #: the list of parameters for this command in the order they - #: should show up in the help page and execute. Eager parameters - #: will automatically be handled before non eager ones. - self.params: list[Parameter] = params or [] - self.help = help - self.epilog = epilog - self.options_metavar = options_metavar - self.short_help = short_help - self.add_help_option = add_help_option - self._help_option = None - self.no_args_is_help = no_args_is_help - self.hidden = hidden - self.deprecated = deprecated - - def to_info_dict(self, ctx: Context) -> dict[str, t.Any]: - return { - "name": self.name, - "params": [param.to_info_dict() for param in self.get_params(ctx)], - "help": self.help, - "epilog": self.epilog, - "short_help": self.short_help, - "hidden": self.hidden, - "deprecated": self.deprecated, - } - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} {self.name}>" - - def get_usage(self, ctx: Context) -> str: - """Formats the usage line into a string and returns it. - - Calls :meth:`format_usage` internally. - """ - formatter = ctx.make_formatter() - self.format_usage(ctx, formatter) - return formatter.getvalue().rstrip("\n") - - def get_params(self, ctx: Context) -> list[Parameter]: - params = self.params - help_option = self.get_help_option(ctx) - - if help_option is not None: - params = [*params, help_option] - - if __debug__: - import warnings - - opts = [opt for param in params for opt in param.opts] - opts_counter = Counter(opts) - duplicate_opts = (opt for opt, count in opts_counter.items() if count > 1) - - for duplicate_opt in duplicate_opts: - warnings.warn( - ( - f"The parameter {duplicate_opt} is used more than once. " - "Remove its duplicate as parameters should be unique." - ), - stacklevel=3, - ) - - return params - - def format_usage(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes the usage line into the formatter. - - This is a low-level method called by :meth:`get_usage`. - """ - pieces = self.collect_usage_pieces(ctx) - formatter.write_usage(ctx.command_path, " ".join(pieces)) - - def collect_usage_pieces(self, ctx: Context) -> list[str]: - """Returns all the pieces that go into the usage line and returns - it as a list of strings. - """ - rv = [self.options_metavar] if self.options_metavar else [] - - for param in self.get_params(ctx): - rv.extend(param.get_usage_pieces(ctx)) - - return rv - - def get_help_option_names(self, ctx: Context) -> list[str]: - """Returns the names for the help option.""" - all_names = set(ctx.help_option_names) - for param in self.params: - all_names.difference_update(param.opts) - all_names.difference_update(param.secondary_opts) - return list(all_names) - - def get_help_option(self, ctx: Context) -> Option | None: - """Returns the help option object. - - Skipped if :attr:`add_help_option` is ``False``. - - .. versionchanged:: 8.1.8 - The help option is now cached to avoid creating it multiple times. - """ - help_option_names = self.get_help_option_names(ctx) - - if not help_option_names or not self.add_help_option: - return None - - # Cache the help option object in private _help_option attribute to - # avoid creating it multiple times. Not doing this will break the - # callback ordering by iter_params_for_processing(), which relies on - # object comparison. - if self._help_option is None: - # Avoid circular import. - from .decorators import help_option - - # Apply help_option decorator and pop resulting option - help_option(*help_option_names)(self) - self._help_option = self.params.pop() # type: ignore[assignment] - - return self._help_option - - def make_parser(self, ctx: Context) -> _OptionParser: - """Creates the underlying option parser for this command.""" - parser = _OptionParser(ctx) - for param in self.get_params(ctx): - param.add_to_parser(parser, ctx) - return parser - - def get_help(self, ctx: Context) -> str: - """Formats the help into a string and returns it. - - Calls :meth:`format_help` internally. - """ - formatter = ctx.make_formatter() - self.format_help(ctx, formatter) - return formatter.getvalue().rstrip("\n") - - def get_short_help_str(self, limit: int = 45) -> str: - """Gets short help for the command or makes it by shortening the - long help string. - """ - if self.short_help: - text = inspect.cleandoc(self.short_help) - elif self.help: - text = make_default_short_help(self.help, limit) - else: - text = "" - - if self.deprecated: - text = f"{_(text)} {_format_deprecated_label(self.deprecated)}" - - return text.strip() - - def format_help(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes the help into the formatter if it exists. - - This is a low-level method called by :meth:`get_help`. - - This calls the following methods: - - - :meth:`format_usage` - - :meth:`format_help_text` - - :meth:`format_options` - - :meth:`format_epilog` - """ - self.format_usage(ctx, formatter) - self.format_help_text(ctx, formatter) - self.format_options(ctx, formatter) - self.format_epilog(ctx, formatter) - - def format_help_text(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes the help text to the formatter if it exists.""" - if self.help is not None: - # truncate the help text to the first form feed - text = inspect.cleandoc(self.help).partition("\f")[0] - else: - text = "" - - if self.deprecated: - text = f"{_(text)} {_format_deprecated_label(self.deprecated)}" - - if text: - formatter.write_paragraph() - - with formatter.indentation(): - formatter.write_text(text) - - def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes all the options into the formatter if they exist.""" - opts = [] - for param in self.get_params(ctx): - rv = param.get_help_record(ctx) - if rv is not None: - opts.append(rv) - - if opts: - with formatter.section(_("Options")): - formatter.write_dl(opts) - - def format_epilog(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes the epilog into the formatter if it exists.""" - if self.epilog: - epilog = inspect.cleandoc(self.epilog) - formatter.write_paragraph() - - with formatter.indentation(): - formatter.write_text(epilog) - - def make_context( - self, - info_name: str | None, - args: list[str], - parent: Context | None = None, - **extra: t.Any, - ) -> Context: - """This function when given an info name and arguments will kick - off the parsing and create a new :class:`Context`. It does not - invoke the actual command callback though. - - To quickly customize the context class used without overriding - this method, set the :attr:`context_class` attribute. - - :param info_name: the info name for this invocation. Generally this - is the most descriptive name for the script or - command. For the toplevel script it's usually - the name of the script, for commands below it's - the name of the command. - :param args: the arguments to parse as list of strings. - :param parent: the parent context if available. - :param extra: extra keyword arguments forwarded to the context - constructor. - - .. versionchanged:: 8.0 - Added the :attr:`context_class` attribute. - """ - for key, value in self.context_settings.items(): - if key not in extra: - extra[key] = value - - ctx = self.context_class(self, info_name=info_name, parent=parent, **extra) - - with ctx.scope(cleanup=False): - self.parse_args(ctx, args) - return ctx - - def parse_args(self, ctx: Context, args: list[str]) -> list[str]: - if not args and self.no_args_is_help and not ctx.resilient_parsing: - raise NoArgsIsHelpError(ctx) - - parser = self.make_parser(ctx) - opts, args, param_order = parser.parse_args(args=args) - - for param in iter_params_for_processing(param_order, self.get_params(ctx)): - _, args = param.handle_parse_result(ctx, opts, args) - - # We now have all parameters' values into `ctx.params`, but the data may contain - # the `UNSET` sentinel. - # Convert `UNSET` to `None` to ensure that the user doesn't see `UNSET`. - # - # Waiting until after the initial parse to convert allows us to treat `UNSET` - # more like a missing value when multiple params use the same name. - # Refs: - # https://github.com/pallets/click/issues/3071 - # https://github.com/pallets/click/pull/3079 - for name, value in ctx.params.items(): - if value is UNSET: - ctx.params[name] = None - - 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.{extra_message}" - ).format( - name=self.name, - extra_message=_format_deprecated_suffix(self.deprecated), - ) - echo(style(message, fg="red"), err=True) - - if self.callback is not None: - return ctx.invoke(self.callback, **ctx.params) - - def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: - """Return a list of completions for the incomplete value. Looks - at the names of options and chained multi-commands. - - Any command could be part of a chained multi-command, so sibling - commands are valid at any point during command completion. - - :param ctx: Invocation context for this command. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - results: list[CompletionItem] = [] - - if incomplete and not incomplete[0].isalnum(): - for param in self.get_params(ctx): - if ( - not isinstance(param, Option) - or param.hidden - or ( - not param.multiple - and ctx.get_parameter_source(param.name) - is ParameterSource.COMMANDLINE - ) - ): - continue - - results.extend( - CompletionItem(name, help=param.help) - for name in [*param.opts, *param.secondary_opts] - if name.startswith(incomplete) - ) - - while ctx.parent is not None: - ctx = ctx.parent - - if isinstance(ctx.command, Group) and ctx.command.chain: - results.extend( - CompletionItem(name, help=command.get_short_help_str()) - for name, command in _complete_visible_commands(ctx, incomplete) - if name not in ctx._protected_args - ) - - return results - - @t.overload - def main( - self, - args: cabc.Sequence[str] | None = None, - prog_name: str | None = None, - complete_var: str | None = None, - standalone_mode: t.Literal[True] = True, - **extra: t.Any, - ) -> t.NoReturn: ... - - @t.overload - def main( - self, - args: cabc.Sequence[str] | None = None, - prog_name: str | None = None, - complete_var: str | None = None, - standalone_mode: bool = ..., - **extra: t.Any, - ) -> t.Any: ... - - def main( - self, - args: cabc.Sequence[str] | None = None, - prog_name: str | None = None, - complete_var: str | None = None, - standalone_mode: bool = True, - windows_expand_args: bool = True, - **extra: t.Any, - ) -> t.Any: - """This is the way to invoke a script with all the bells and - whistles as a command line application. This will always terminate - the application after a call. If this is not wanted, ``SystemExit`` - needs to be caught. - - This method is also available by directly calling the instance of - a :class:`Command`. - - :param args: the arguments that should be used for parsing. If not - provided, ``sys.argv[1:]`` is used. - :param prog_name: the program name that should be used. By default - the program name is constructed by taking the file - name from ``sys.argv[0]``. - :param complete_var: the environment variable that controls the - bash completion support. The default is - ``"__COMPLETE"`` with prog_name in - uppercase. - :param standalone_mode: the default behavior is to invoke the script - in standalone mode. Click will then - handle exceptions and convert them into - error messages and the function will never - return but shut down the interpreter. If - this is set to `False` they will be - propagated to the caller and the return - value of this function is the return value - of :meth:`invoke`. - :param windows_expand_args: Expand glob patterns, user dir, and - env vars in command line args on Windows. - :param extra: extra keyword arguments are forwarded to the context - constructor. See :class:`Context` for more information. - - .. versionchanged:: 8.0.1 - Added the ``windows_expand_args`` parameter to allow - disabling command line arg expansion on Windows. - - .. versionchanged:: 8.0 - When taking arguments from ``sys.argv`` on Windows, glob - patterns, user dir, and env vars are expanded. - - .. versionchanged:: 3.0 - Added the ``standalone_mode`` parameter. - """ - if args is None: - args = sys.argv[1:] - - if os.name == "nt" and windows_expand_args: - args = _expand_args(args) - else: - args = list(args) - - if prog_name is None: - prog_name = _detect_program_name() - - # Process shell completion requests and exit early. - self._main_shell_completion(extra, prog_name, complete_var) - - try: - try: - with self.make_context(prog_name, args, **extra) as ctx: - rv = self.invoke(ctx) - if not standalone_mode: - return rv - # it's not safe to `ctx.exit(rv)` here! - # note that `rv` may actually contain data like "1" which - # has obvious effects - # more subtle case: `rv=[None, None]` can come out of - # chained commands which all returned `None` -- so it's not - # even always obvious that `rv` indicates success/failure - # by its truthiness/falsiness - ctx.exit() - except (EOFError, KeyboardInterrupt) as e: - echo(file=sys.stderr) - raise Abort() from e - except ClickException as e: - if not standalone_mode: - raise - e.show() - sys.exit(e.exit_code) - except OSError as e: - if e.errno == errno.EPIPE: - sys.stdout = t.cast(t.TextIO, PacifyFlushWrapper(sys.stdout)) - sys.stderr = t.cast(t.TextIO, PacifyFlushWrapper(sys.stderr)) - sys.exit(1) - else: - raise - except Exit as e: - if standalone_mode: - sys.exit(e.exit_code) - else: - # in non-standalone mode, return the exit code - # note that this is only reached if `self.invoke` above raises - # an Exit explicitly -- thus bypassing the check there which - # would return its result - # the results of non-standalone execution may therefore be - # somewhat ambiguous: if there are codepaths which lead to - # `ctx.exit(1)` and to `return 1`, the caller won't be able to - # tell the difference between the two - return e.exit_code - except Abort: - if not standalone_mode: - raise - echo(_("Aborted!"), file=sys.stderr) - sys.exit(1) - - def _main_shell_completion( - self, - ctx_args: cabc.MutableMapping[str, t.Any], - prog_name: str, - complete_var: str | None = None, - ) -> None: - """Check if the shell is asking for tab completion, process - that, then exit early. Called from :meth:`main` before the - program is invoked. - - :param prog_name: Name of the executable in the shell. - :param complete_var: Name of the environment variable that holds - the completion instruction. Defaults to - ``_{PROG_NAME}_COMPLETE``. - - .. versionchanged:: 8.2.0 - Dots (``.``) in ``prog_name`` are replaced with underscores (``_``). - """ - if complete_var is None: - complete_name = prog_name.replace("-", "_").replace(".", "_") - complete_var = f"_{complete_name}_COMPLETE".upper() - - instruction = os.environ.get(complete_var) - - if not instruction: - return - - from .shell_completion import shell_complete - - rv = shell_complete(self, ctx_args, prog_name, complete_var, instruction) - sys.exit(rv) - - def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any: - """Alias for :meth:`main`.""" - return self.main(*args, **kwargs) - - -class _FakeSubclassCheck(type): - def __subclasscheck__(cls, subclass: type) -> bool: - return issubclass(subclass, cls.__bases__[0]) - - def __instancecheck__(cls, instance: t.Any) -> bool: - return isinstance(instance, cls.__bases__[0]) - - -class _BaseCommand(Command, metaclass=_FakeSubclassCheck): - """ - .. deprecated:: 8.2 - Will be removed in Click 9.0. Use ``Command`` instead. - """ - - -class Group(Command): - """A group is a command that nests other commands (or more groups). - - :param name: The name of the group command. - :param commands: Map names to :class:`Command` objects. Can be a list, which - will use :attr:`Command.name` as the keys. - :param invoke_without_command: Invoke the group's callback even if a - subcommand is not given. - :param no_args_is_help: If no arguments are given, show the group's help and - exit. Defaults to the opposite of ``invoke_without_command``. - :param subcommand_metavar: How to represent the subcommand argument in help. - The default will represent whether ``chain`` is set or not. - :param chain: Allow passing more than one subcommand argument. After parsing - a command's arguments, if any arguments remain another command will be - matched, and so on. - :param result_callback: A function to call after the group's and - subcommand's callbacks. The value returned by the subcommand is passed. - If ``chain`` is enabled, the value will be a list of values returned by - all the commands. If ``invoke_without_command`` is enabled, the value - will be the value returned by the group's callback, or an empty list if - ``chain`` is enabled. - :param kwargs: Other arguments passed to :class:`Command`. - - .. versionchanged:: 8.0 - The ``commands`` argument can be a list of command objects. - - .. versionchanged:: 8.2 - Merged with and replaces the ``MultiCommand`` base class. - """ - - allow_extra_args = True - allow_interspersed_args = False - - #: If set, this is used by the group's :meth:`command` decorator - #: as the default :class:`Command` class. This is useful to make all - #: subcommands use a custom command class. - #: - #: .. versionadded:: 8.0 - command_class: type[Command] | None = None - - #: If set, this is used by the group's :meth:`group` decorator - #: as the default :class:`Group` class. This is useful to make all - #: subgroups use a custom group class. - #: - #: If set to the special value :class:`type` (literally - #: ``group_class = type``), this group's class will be used as the - #: default class. This makes a custom group class continue to make - #: custom groups. - #: - #: .. versionadded:: 8.0 - group_class: type[Group] | type[type] | None = None - # Literal[type] isn't valid, so use Type[type] - - def __init__( - self, - name: str | None = None, - commands: cabc.MutableMapping[str, Command] - | cabc.Sequence[Command] - | None = None, - invoke_without_command: bool = False, - no_args_is_help: bool | None = None, - subcommand_metavar: str | None = None, - chain: bool = False, - result_callback: t.Callable[..., t.Any] | None = None, - **kwargs: t.Any, - ) -> None: - super().__init__(name, **kwargs) - - if commands is None: - commands = {} - elif isinstance(commands, abc.Sequence): - commands = {c.name: c for c in commands if c.name is not None} - - #: The registered subcommands by their exported names. - self.commands: cabc.MutableMapping[str, Command] = commands - - if no_args_is_help is None: - no_args_is_help = not invoke_without_command - - self.no_args_is_help = no_args_is_help - self.invoke_without_command = invoke_without_command - - if subcommand_metavar is None: - if chain: - subcommand_metavar = "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..." - else: - subcommand_metavar = "COMMAND [ARGS]..." - - self.subcommand_metavar = subcommand_metavar - self.chain = chain - # The result callback that is stored. This can be set or - # overridden with the :func:`result_callback` decorator. - self._result_callback = result_callback - - if self.chain: - for param in self.params: - if isinstance(param, Argument) and not param.required: - raise RuntimeError( - "A group in chain mode cannot have optional arguments." - ) - - def to_info_dict(self, ctx: Context) -> dict[str, t.Any]: - info_dict = super().to_info_dict(ctx) - commands = {} - - for name in self.list_commands(ctx): - command = self.get_command(ctx, name) - - if command is None: - continue - - sub_ctx = ctx._make_sub_context(command) - - with sub_ctx.scope(cleanup=False): - commands[name] = command.to_info_dict(sub_ctx) - - info_dict.update(commands=commands, chain=self.chain) - return info_dict - - def add_command(self, cmd: Command, name: str | None = None) -> None: - """Registers another :class:`Command` with this group. If the name - is not provided, the name of the command is used. - """ - name = name or cmd.name - if name is None: - raise TypeError("Command has no name.") - _check_nested_chain(self, name, cmd, register=True) - self.commands[name] = cmd - - @t.overload - def command(self, __func: t.Callable[..., t.Any]) -> Command: ... - - @t.overload - def command( - self, *args: t.Any, **kwargs: t.Any - ) -> t.Callable[[t.Callable[..., t.Any]], Command]: ... - - def command( - self, *args: t.Any, **kwargs: t.Any - ) -> t.Callable[[t.Callable[..., t.Any]], Command] | Command: - """A shortcut decorator for declaring and attaching a command to - the group. This takes the same arguments as :func:`command` and - immediately registers the created command with this group by - calling :meth:`add_command`. - - To customize the command class used, set the - :attr:`command_class` attribute. - - .. versionchanged:: 8.1 - This decorator can be applied without parentheses. - - .. versionchanged:: 8.0 - Added the :attr:`command_class` attribute. - """ - from .decorators import command - - func: t.Callable[..., t.Any] | None = None - - if args and callable(args[0]): - assert len(args) == 1 and not kwargs, ( - "Use 'command(**kwargs)(callable)' to provide arguments." - ) - (func,) = args - args = () - - if self.command_class and kwargs.get("cls") is None: - kwargs["cls"] = self.command_class - - def decorator(f: t.Callable[..., t.Any]) -> Command: - cmd: Command = command(*args, **kwargs)(f) - self.add_command(cmd) - return cmd - - if func is not None: - return decorator(func) - - return decorator - - @t.overload - def group(self, __func: t.Callable[..., t.Any]) -> Group: ... - - @t.overload - def group( - self, *args: t.Any, **kwargs: t.Any - ) -> t.Callable[[t.Callable[..., t.Any]], Group]: ... - - def group( - self, *args: t.Any, **kwargs: t.Any - ) -> t.Callable[[t.Callable[..., t.Any]], Group] | Group: - """A shortcut decorator for declaring and attaching a group to - the group. This takes the same arguments as :func:`group` and - immediately registers the created group with this group by - calling :meth:`add_command`. - - To customize the group class used, set the :attr:`group_class` - attribute. - - .. versionchanged:: 8.1 - This decorator can be applied without parentheses. - - .. versionchanged:: 8.0 - Added the :attr:`group_class` attribute. - """ - from .decorators import group - - func: t.Callable[..., t.Any] | None = None - - if args and callable(args[0]): - assert len(args) == 1 and not kwargs, ( - "Use 'group(**kwargs)(callable)' to provide arguments." - ) - (func,) = args - args = () - - if self.group_class is not None and kwargs.get("cls") is None: - if self.group_class is type: - kwargs["cls"] = type(self) - else: - kwargs["cls"] = self.group_class - - def decorator(f: t.Callable[..., t.Any]) -> Group: - cmd: Group = group(*args, **kwargs)(f) - self.add_command(cmd) - return cmd - - if func is not None: - return decorator(func) - - return decorator - - def result_callback(self, replace: bool = False) -> t.Callable[[F], F]: - """Adds a result callback to the command. By default if a - result callback is already registered this will chain them but - this can be disabled with the `replace` parameter. The result - callback is invoked with the return value of the subcommand - (or the list of return values from all subcommands if chaining - is enabled) as well as the parameters as they would be passed - to the main callback. - - Example:: - - @click.group() - @click.option('-i', '--input', default=23) - def cli(input): - return 42 - - @cli.result_callback() - def process_result(result, input): - return result + input - - :param replace: if set to `True` an already existing result - callback will be removed. - - .. versionchanged:: 8.0 - Renamed from ``resultcallback``. - - .. versionadded:: 3.0 - """ - - def decorator(f: F) -> F: - old_callback = self._result_callback - - if old_callback is None or replace: - self._result_callback = f - return f - - def function(value: t.Any, /, *args: t.Any, **kwargs: t.Any) -> t.Any: - inner = old_callback(value, *args, **kwargs) - return f(inner, *args, **kwargs) - - self._result_callback = rv = update_wrapper(t.cast(F, function), f) - return rv # type: ignore[return-value] - - return decorator - - def get_command(self, ctx: Context, cmd_name: str) -> Command | None: - """Given a context and a command name, this returns a :class:`Command` - object if it exists or returns ``None``. - """ - return self.commands.get(cmd_name) - - def list_commands(self, ctx: Context) -> list[str]: - """Returns a list of subcommand names in the order they should appear.""" - return sorted(self.commands) - - def collect_usage_pieces(self, ctx: Context) -> list[str]: - rv = super().collect_usage_pieces(ctx) - rv.append(self.subcommand_metavar) - return rv - - def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: - super().format_options(ctx, formatter) - self.format_commands(ctx, formatter) - - def format_commands(self, ctx: Context, formatter: HelpFormatter) -> None: - """Extra format methods for multi methods that adds all the commands - after the options. - """ - commands = [] - for subcommand in self.list_commands(ctx): - cmd = self.get_command(ctx, subcommand) - # What is this, the tool lied about a command. Ignore it - if cmd is None: - continue - if cmd.hidden: - continue - - commands.append((subcommand, cmd)) - - # allow for 3 times the default spacing - if len(commands): - limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands) - - rows = [] - for subcommand, cmd in commands: - help = cmd.get_short_help_str(limit) - rows.append((subcommand, help)) - - if rows: - with formatter.section(_("Commands")): - formatter.write_dl(rows) - - def parse_args(self, ctx: Context, args: list[str]) -> list[str]: - if not args and self.no_args_is_help and not ctx.resilient_parsing: - raise NoArgsIsHelpError(ctx) - - rest = super().parse_args(ctx, args) - - if self.chain: - ctx._protected_args = rest - ctx.args = [] - elif rest: - ctx._protected_args, ctx.args = rest[:1], rest[1:] - - return ctx.args - - def invoke(self, ctx: Context) -> t.Any: - def _process_result(value: t.Any) -> t.Any: - if self._result_callback is not None: - value = ctx.invoke(self._result_callback, value, **ctx.params) - return value - - if not ctx._protected_args: - if self.invoke_without_command: - # No subcommand was invoked, so the result callback is - # invoked with the group return value for regular - # groups, or an empty list for chained groups. - with ctx: - rv = super().invoke(ctx) - return _process_result([] if self.chain else rv) - ctx.fail(_("Missing command.")) - - # Fetch args back out - args = [*ctx._protected_args, *ctx.args] - ctx.args = [] - ctx._protected_args = [] - - # If we're not in chain mode, we only allow the invocation of a - # single command but we also inform the current context about the - # name of the command to invoke. - if not self.chain: - # Make sure the context is entered so we do not clean up - # resources until the result processor has worked. - with ctx: - cmd_name, cmd, args = self.resolve_command(ctx, args) - assert cmd is not None - ctx.invoked_subcommand = cmd_name - super().invoke(ctx) - sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) - with sub_ctx: - return _process_result(sub_ctx.command.invoke(sub_ctx)) - - # In chain mode we create the contexts step by step, but after the - # base command has been invoked. Because at that point we do not - # know the subcommands yet, the invoked subcommand attribute is - # set to ``*`` to inform the command that subcommands are executed - # but nothing else. - with ctx: - ctx.invoked_subcommand = "*" if args else None - super().invoke(ctx) - - # Otherwise we make every single context and invoke them in a - # chain. In that case the return value to the result processor - # is the list of all invoked subcommand's results. - contexts = [] - while args: - cmd_name, cmd, args = self.resolve_command(ctx, args) - assert cmd is not None - sub_ctx = cmd.make_context( - cmd_name, - args, - parent=ctx, - allow_extra_args=True, - allow_interspersed_args=False, - ) - contexts.append(sub_ctx) - args, sub_ctx.args = sub_ctx.args, [] - - rv = [] - for sub_ctx in contexts: - with sub_ctx: - rv.append(sub_ctx.command.invoke(sub_ctx)) - return _process_result(rv) - - def resolve_command( - self, ctx: Context, args: list[str] - ) -> tuple[str | None, Command | None, list[str]]: - cmd_name = make_str(args[0]) - - # Get the command - cmd = self.get_command(ctx, cmd_name) - - # If we can't find the command but there is a normalization - # function available, we try with that one. - if cmd is None and ctx.token_normalize_func is not None: - cmd_name = ctx.token_normalize_func(cmd_name) - cmd = self.get_command(ctx, cmd_name) - - # If we don't find the command we want to show an error message - # to the user that it was not provided. However, there is - # something else we should do: if the first argument looks like - # an option we want to kick off parsing again for arguments to - # resolve things like --help which now should go to the main - # place. - if cmd is None and not ctx.resilient_parsing: - if _split_opt(cmd_name)[0]: - self.parse_args(ctx, args) - raise NoSuchCommand(cmd_name, possibilities=self.commands, ctx=ctx) - return cmd_name if cmd else None, cmd, args[1:] - - def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: - """Return a list of completions for the incomplete value. Looks - at the names of options, subcommands, and chained - multi-commands. - - :param ctx: Invocation context for this command. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - results = [ - CompletionItem(name, help=command.get_short_help_str()) - for name, command in _complete_visible_commands(ctx, incomplete) - ] - results.extend(super().shell_complete(ctx, incomplete)) - return results - - -class _MultiCommand(Group, metaclass=_FakeSubclassCheck): - """ - .. deprecated:: 8.2 - Will be removed in Click 9.0. Use ``Group`` instead. - """ - - -class CommandCollection(Group): - """A :class:`Group` that looks up subcommands on other groups. If a command - is not found on this group, each registered source is checked in order. - Parameters on a source are not added to this group, and a source's callback - is not invoked when invoking its commands. In other words, this "flattens" - commands in many groups into this one group. - - :param name: The name of the group command. - :param sources: A list of :class:`Group` objects to look up commands from. - :param kwargs: Other arguments passed to :class:`Group`. - - .. versionchanged:: 8.2 - This is a subclass of ``Group``. Commands are looked up first on this - group, then each of its sources. - """ - - def __init__( - self, - name: str | None = None, - sources: list[Group] | None = None, - **kwargs: t.Any, - ) -> None: - super().__init__(name, **kwargs) - #: The list of registered groups. - self.sources: list[Group] = sources or [] - - def add_source(self, group: Group) -> None: - """Add a group as a source of commands.""" - self.sources.append(group) - - def get_command(self, ctx: Context, cmd_name: str) -> Command | None: - rv = super().get_command(ctx, cmd_name) - - if rv is not None: - return rv - - for source in self.sources: - rv = source.get_command(ctx, cmd_name) - - if rv is not None: - if self.chain: - _check_nested_chain(self, cmd_name, rv) - - return rv - - return None - - def list_commands(self, ctx: Context) -> list[str]: - rv: set[str] = set(super().list_commands(ctx)) - - for source in self.sources: - rv.update(source.list_commands(ctx)) - - return sorted(rv) - - -def _check_iter(value: t.Any) -> cabc.Iterator[t.Any]: - """Check if the value is iterable but not a string. Raises a type - error, or return an iterator over the value. - """ - if isinstance(value, str): - raise TypeError - - return iter(value) - - -class Parameter(ABC): - r"""A parameter to a command comes in two versions: they are either - :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently - not supported by design as some of the internals for parsing are - intentionally not finalized. - - Some settings are supported by both options and arguments. - - :param param_decls: the parameter declarations for this option or - argument. This is a list of flags or argument - names. - :param type: the type that should be used. Either a :class:`ParamType` - or a Python type. The latter is converted into the former - automatically if supported. - :param required: controls if this is optional or not. - :param default: the default value if omitted. This can also be a callable, - in which case it's invoked when the default is needed - without any arguments. - :param callback: A function to further process or validate the value - after type conversion. It is called as ``f(ctx, param, value)`` - and must return the value. It is called for all sources, - including prompts. - :param nargs: the number of arguments to match. If not ``1`` the return - value is a tuple instead of single value. The default for - nargs is ``1`` (except if the type is a tuple, then it's - the arity of the tuple). If ``nargs=-1``, all remaining - parameters are collected. - :param metavar: how the value is represented in the help page. - :param expose_value: if this is `True` then the value is passed onwards - to the command callback and stored on the context, - otherwise it's skipped. - :param is_eager: eager values are processed before non eager ones. This - should not be set for arguments or it will inverse the - order of processing. - :param envvar: environment variable(s) that are used to provide a default value for - this parameter. This can be a string or a sequence of strings. If a sequence is - given, only the first non-empty environment variable is used for the parameter. - :param shell_complete: A function that returns custom shell - completions. Used instead of the param's type completion if - given. Takes ``ctx, param, incomplete`` and must return a list - of :class:`~click.shell_completion.CompletionItem` or a list of - strings. - :param deprecated: If ``True`` or non-empty string, issues a message - indicating that the argument is deprecated and highlights - its deprecation in --help. The message can be customized - by using a string as the value. A deprecated parameter - cannot be required, a ValueError will be raised otherwise. - - .. versionchanged:: 8.2.0 - Introduction of ``deprecated``. - - .. versionchanged:: 8.2 - Adding duplicate parameter names to a :class:`~click.core.Command` will - result in a ``UserWarning`` being shown. - - .. versionchanged:: 8.2 - Adding duplicate parameter names to a :class:`~click.core.Command` will - result in a ``UserWarning`` being shown. - - .. versionchanged:: 8.0 - ``process_value`` validates required parameters and bounded - ``nargs``, and invokes the parameter callback before returning - the value. This allows the callback to validate prompts. - ``full_process_value`` is removed. - - .. versionchanged:: 8.0 - ``autocompletion`` is renamed to ``shell_complete`` and has new - semantics described above. The old name is deprecated and will - be removed in 8.1, until then it will be wrapped to match the - new requirements. - - .. versionchanged:: 8.0 - For ``multiple=True, nargs>1``, the default must be a list of - tuples. - - .. versionchanged:: 8.0 - Setting a default is no longer required for ``nargs>1``, it will - default to ``None``. ``multiple=True`` or ``nargs=-1`` will - default to ``()``. - - .. versionchanged:: 7.1 - Empty environment variables are ignored rather than taking the - empty string value. This makes it possible for scripts to clear - variables if they can't unset them. - - .. versionchanged:: 2.0 - Changed signature for parameter callback to also be passed the - parameter. The old callback format will still work, but it will - raise a warning to give you a chance to migrate the code easier. - """ - - param_type_name = "parameter" - - def __init__( - self, - param_decls: cabc.Sequence[str] | None = None, - type: types.ParamType[t.Any] | t.Any | None = None, - required: bool = False, - # XXX The default historically embed two concepts: - # - the declaration of a Parameter object carrying the default (handy to - # arbitrage the default value of coupled Parameters sharing the same - # self.name, like flag options), - # - and the actual value of the default. - # It is confusing and is the source of many issues discussed in: - # https://github.com/pallets/click/pull/3030 - # In the future, we might think of splitting it in two, not unlike - # Option.is_flag and Option.flag_value: we could have something like - # Parameter.is_default and Parameter.default_value. - default: t.Any | t.Callable[[], t.Any] | None = UNSET, - callback: t.Callable[[Context, Parameter, t.Any], t.Any] | None = None, - nargs: int | None = None, - multiple: bool = False, - metavar: str | None = None, - expose_value: bool = True, - is_eager: bool = False, - envvar: str | cabc.Sequence[str] | None = None, - shell_complete: t.Callable[ - [Context, Parameter, str], list[CompletionItem] | list[str] - ] - | None = None, - deprecated: bool | str = False, - ) -> None: - self.name: str - self.opts: list[str] - self.secondary_opts: list[str] - self.name, self.opts, self.secondary_opts = self._parse_decls( - param_decls or (), expose_value - ) - self.type: types.ParamType[t.Any] = 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: t.Any | t.Callable[[], t.Any] | None = default - # Whether the user passed ``default`` explicitly to the constructor. - # Captured before any auto-derived default (like ``False`` for boolean - # flags in :class:`Option`) replaces the :data:`UNSET` sentinel, so it - # remains ``False`` when the default was inferred rather than chosen. - # Refs: https://github.com/pallets/click/issues/3403 - self._default_explicit: bool = default is not UNSET - self.is_eager = is_eager - self.metavar = metavar - self.envvar = envvar - self._custom_shell_complete = shell_complete - self.deprecated = deprecated - - if __debug__: - if self.type.is_composite and nargs != self.type.arity: - raise ValueError( - f"'nargs' must be {self.type.arity} (or None) for" - f" type {self.type!r}, but it was {nargs}." - ) - - if required and deprecated: - raise ValueError( - f"The {self.param_type_name} '{self.human_readable_name}' " - "is deprecated and still required. A deprecated " - f"{self.param_type_name} cannot be required." - ) - - def to_info_dict(self) -> dict[str, t.Any]: - """Gather information that could be useful for a tool generating - user-facing documentation. - - Use :meth:`click.Context.to_info_dict` to traverse the entire - CLI structure. - - .. versionchanged:: 8.3.0 - Returns ``None`` for the :attr:`default` if it was not set. - - .. 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, - # We explicitly hide the :attr:`UNSET` value to the user, as we choose to - # make it an implementation detail. And because ``to_info_dict`` has been - # designed for documentation purposes, we return ``None`` instead. - "default": self.default if self.default is not UNSET else None, - "envvar": self.envvar, - } - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} {self.name}>" - - @abstractmethod - def _parse_decls( - self, decls: cabc.Sequence[str], expose_value: bool - ) -> tuple[str, list[str], list[str]]: ... - - @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 - - def make_metavar(self, ctx: Context) -> str: - if self.metavar is not None: - return self.metavar - - metavar = self.type.get_metavar(param=self, ctx=ctx) - - if metavar is None: - metavar = self.type.name.upper() - - if self.nargs != 1: - metavar += "..." - - return metavar - - @t.overload - def get_default( - self, ctx: Context, call: t.Literal[True] = True - ) -> t.Any | None: ... - - @t.overload - def get_default( - self, ctx: Context, call: bool = ... - ) -> t.Any | t.Callable[[], t.Any] | None: ... - - def get_default( - self, ctx: Context, call: bool = True - ) -> t.Any | t.Callable[[], t.Any] | None: - """Get the default for the parameter. Tries - :meth:`Context.lookup_default` first, then the local default. - - :param ctx: Current context. - :param call: If the default is a callable, call it. Disable to - return the callable instead. - - .. versionchanged:: 8.0.2 - Type casting is no longer performed when getting a default. - - .. versionchanged:: 8.0.1 - Type casting can fail in resilient parsing mode. Invalid - defaults will not prevent showing help text. - - .. versionchanged:: 8.0 - Looks at ``ctx.default_map`` first. - - .. versionchanged:: 8.0 - Added the ``call`` parameter. - """ - value = ctx.lookup_default(self.name, call=False) - - if value is None and not ctx._default_map_has(self.name): - value = self.default - - if call and callable(value): - value = value() - - return value - - @abstractmethod - def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: ... - - def consume_value( - self, ctx: Context, opts: cabc.Mapping[str, t.Any] - ) -> tuple[t.Any, ParameterSource]: - """Returns the parameter value produced by the parser. - - If the parser did not produce a value from user input, the value is either - sourced from the environment variable, the default map, or the parameter's - default value. In that order of precedence. - - If no value is found, an internal sentinel value is returned. - - :meta private: - """ - # Collect from the parse the value passed by the user to the CLI. - value = opts.get(self.name, UNSET) - # If the value is set, it means it was sourced from the command line by the - # parser, otherwise it left unset by default. - source = ( - ParameterSource.COMMANDLINE - if value is not UNSET - else ParameterSource.DEFAULT - ) - - if value is UNSET: - envvar_value = self.value_from_envvar(ctx) - if envvar_value is not None: - value = envvar_value - source = ParameterSource.ENVIRONMENT - - if value is UNSET: - default_map_value = ctx.lookup_default(self.name) - if default_map_value is not None or ctx._default_map_has(self.name): - value = default_map_value - source = ParameterSource.DEFAULT_MAP - - # A string from default_map must be split for multi-value - # parameters, matching value_from_envvar behavior. - if isinstance(value, str) and self.nargs != 1: - value = self.type.split_envvar_value(value) - - if value is UNSET: - default_value = self.get_default(ctx) - if default_value is not UNSET: - value = default_value - 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 parameter's - :attr:`type`, :attr:`multiple`, and :attr:`nargs`. - """ - if value is None: - if self.multiple or self.nargs == -1: - return () - else: - return value - - def check_iter(value: t.Any) -> cabc.Iterator[t.Any]: - try: - return _check_iter(value) - except TypeError: - # This should only happen when passing in args manually, - # the parser should construct an iterable when parsing - # the command line. - raise BadParameter( - _("Value must be an iterable."), ctx=ctx, param=self - ) from None - - # Define the conversion function based on nargs and type. - - if self.nargs == 1 or self.type.is_composite: - - def convert(value: t.Any) -> t.Any: - return self.type(value, param=self, ctx=ctx) - - elif self.nargs == -1: - - def convert(value: t.Any) -> t.Any: # tuple[t.Any, ...] - return tuple(self.type(x, self, ctx) for x in check_iter(value)) - - else: # nargs > 1 - - def convert(value: t.Any) -> t.Any: # tuple[t.Any, ...] - value = tuple(check_iter(value)) - - if len(value) != self.nargs: - raise BadParameter( - ngettext( - "Takes {nargs} values but 1 was given.", - "Takes {nargs} values but {len} were given.", - len(value), - ).format(nargs=self.nargs, len=len(value)), - ctx=ctx, - param=self, - ) - - return tuple(self.type(x, self, ctx) for x in value) - - if self.multiple: - return tuple(convert(x) for x in check_iter(value)) - - return convert(value) - - def value_is_missing(self, value: t.Any) -> bool: - """A value is considered missing if: - - - it is :attr:`UNSET`, - - or if it is an empty sequence while the parameter is suppose to have - non-single value (i.e. :attr:`nargs` is not ``1`` or :attr:`multiple` is - set). - - :meta private: - """ - if value is UNSET: - 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: - """Process the value of this parameter: - - 1. Type cast the value using :meth:`type_cast_value`. - 2. Check if the value is missing (see: :meth:`value_is_missing`), and raise - :exc:`MissingParameter` if it is required. - 3. If a :attr:`callback` is set, call it to have the value replaced by the - result of the callback. If the value was not set, the callback receive - ``None``. This keep the legacy behavior as it was before the introduction of - the :attr:`UNSET` sentinel. - - :meta private: - """ - # shelter `type_cast_value` from ever seeing an `UNSET` value by handling the - # cases in which `UNSET` gets special treatment explicitly at this layer - # - # Refs: - # https://github.com/pallets/click/issues/3069 - if value is UNSET: - if self.multiple or self.nargs == -1: - value = () - else: - 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: - # Legacy case: UNSET is not exposed directly to the callback, but converted - # to None. - if value is UNSET: - value = None - - # Search for parameters with UNSET values in the context. - unset_keys = {k: None for k, v in ctx.params.items() if v is UNSET} - # No UNSET values, call the callback as usual. - if not unset_keys: - value = self.callback(ctx, self, value) - - # Legacy case: provide a temporarily manipulated context to the callback - # to hide UNSET values as None. - # - # Refs: - # https://github.com/pallets/click/issues/3136 - # https://github.com/pallets/click/pull/3137 - else: - # Add another layer to the context stack to clearly hint that the - # context is temporarily modified. - with ctx: - # Update the context parameters to replace UNSET with None. - ctx.params.update(unset_keys) - # Feed these fake context parameters to the callback. - value = self.callback(ctx, self, value) - # Restore the UNSET values in the context parameters. - ctx.params.update( - { - k: UNSET - for k in unset_keys - # Only restore keys that are present and still None, in case - # the callback modified other parameters. - if k in ctx.params and ctx.params[k] is None - } - ) - - return value - - def resolve_envvar_value(self, ctx: Context) -> str | None: - """Returns the value found in the environment variable(s) attached to this - parameter. - - Environment variables values are `always returned as strings - `_. - - This method returns ``None`` if: - - - the :attr:`envvar` property is not set on the :class:`Parameter`, - - the environment variable is not found in the environment, - - the variable is found in the environment but its value is empty (i.e. the - environment variable is present but has an empty string). - - If :attr:`envvar` is setup with multiple environment variables, - then only the first non-empty value is returned. - - .. caution:: - - The raw value extracted from the environment is not normalized and is - returned as-is. Any normalization or reconciliation is performed later by - the :class:`Parameter`'s :attr:`type`. - - :meta private: - """ - if not self.envvar: - 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) - - # Return the first non-empty value of the list of environment variables. - if rv: - return rv - # Else, absence of value is interpreted as an environment variable that - # is not set, so proceed to the next one. - - return None - - def value_from_envvar(self, ctx: Context) -> str | cabc.Sequence[str] | None: - """Process the raw environment variable string for this parameter. - - Returns the string as-is or splits it into a sequence of strings if the - parameter is expecting multiple values (i.e. its :attr:`nargs` property is set - to a value other than ``1``). - - :meta private: - """ - rv = self.resolve_envvar_value(ctx) - - if rv is not None and self.nargs != 1: - return self.type.split_envvar_value(rv) - - return rv - - def handle_parse_result( - self, ctx: Context, opts: cabc.Mapping[str, t.Any], args: list[str] - ) -> tuple[t.Any, list[str]]: - """Process the value produced by the parser from user input. - - Always process the value through the Parameter's :attr:`type`, wherever it - comes from. - - If the parameter is deprecated, this method warn the user about it. But only if - the value has been explicitly set by the user (and as such, is not coming from - a default). - - :meta private: - """ - # Capture the slot's existing state before we mutate - # ``_parameter_source`` so the write decision below can compare our - # incoming source against the source of the option that already wrote - # the slot (if any). - existing_value = ctx.params.get(self.name, UNSET) - existing_source = ctx.get_parameter_source(self.name) - existing_default_explicit = ctx._param_default_explicit.get(self.name, False) - - with augment_usage_errors(ctx, param=self): - value, source = self.consume_value(ctx, opts) - - # Record the source before processing so eager callbacks and type - # conversion can inspect it. Restored after arbitration if this - # option loses a feature-switch group. - ctx.set_parameter_source(self.name, source) - - # Display a deprecation warning if necessary. - if ( - self.deprecated - and value is not UNSET - and source < ParameterSource.DEFAULT_MAP - ): - message = _( - "DeprecationWarning: The {param_type} {name!r} is deprecated." - "{extra_message}" - ).format( - param_type=self.param_type_name, - name=self.human_readable_name, - extra_message=_format_deprecated_suffix(self.deprecated), - ) - echo(style(message, fg="red"), err=True) - - # Process the value through the parameter's type. - try: - value = self.process_value(ctx, value) - except Exception: - if not ctx.resilient_parsing: - raise - # In resilient parsing mode, we do not want to fail the command if the - # value is incompatible with the parameter type, so we reset the value - # to UNSET, which will be interpreted as a missing value. - value = UNSET - - # Arbitrate the slot when several parameters target the same variable - # name (feature-switch groups). See: https://github.com/pallets/click/issues/3403 - slot_empty = existing_value is UNSET - more_explicit = existing_source is not None and source < existing_source - same_source = existing_source is not None and source == existing_source - auto_would_downgrade_explicit = ( - same_source - and source == ParameterSource.DEFAULT - and existing_default_explicit - and not self._default_explicit - ) - is_winner = ( - slot_empty - or more_explicit - or (same_source and not auto_would_downgrade_explicit) - ) - - if is_winner: - if self.expose_value: - ctx.params[self.name] = value - ctx._param_default_explicit[self.name] = self._default_explicit - elif existing_source is not None: - # Lost arbitration; restore the winning option's source. - ctx.set_parameter_source(self.name, existing_source) - # else: ctx.params[self.name] was populated by code that bypassed - # handle_parse_result (from another option's callback for example). Keep - # the provisional source recorded before process_value so downstream - # lookups don't return ``None``. - - return value, args - - def get_help_record(self, ctx: Context) -> tuple[str, str] | None: - return None - - def get_usage_pieces(self, ctx: Context) -> list[str]: - return [] - - def get_error_hint(self, ctx: Context | None) -> str: - """Get a stringified version of the param for use in error messages to - indicate which param caused the error. - - .. versionchanged:: 8.4.0 - ``ctx`` can be ``None``. - """ - hint_list = self.opts or [self.human_readable_name] - return " / ".join(f"'{x}'" for x in hint_list) - - def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: - """Return a list of completions for the incomplete value. If a - ``shell_complete`` function was given during init, it is used. - Otherwise, the :attr:`type` - :meth:`~click.types.ParamType[t.Any].shell_complete` function is used. - - :param ctx: Invocation context for this command. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - if self._custom_shell_complete is not None: - results = self._custom_shell_complete(ctx, self, incomplete) - - if results and isinstance(results[0], str): - from click.shell_completion import CompletionItem - - results = [CompletionItem(c) for c in results] - - return t.cast("list[CompletionItem]", results) - - return self.type.shell_complete(ctx, self, incomplete) - - -class Option(Parameter): - """Options are usually optional values on the command line and - have some extra features that arguments don't have. - - All other parameters are passed onwards to the parameter constructor. - - :param show_default: Show the default value for this option in its - help text. Values are not shown by default, unless - :attr:`Context.show_default` is ``True``. If this value is a - string, it shows that string in parentheses instead of the - actual value. This is particularly useful for dynamic options. - For single option boolean flags, the default remains hidden if - its value is ``False``. - :param show_envvar: Controls if an environment variable should be - shown on the help page and error messages. - Normally, environment variables are not shown. - :param prompt: If set to ``True`` or a non empty string then the - user will be prompted for input. If set to ``True`` the prompt - will be the option name capitalized. A deprecated option cannot be - prompted. - :param confirmation_prompt: Prompt a second time to confirm the - value if it was prompted for. Can be set to a string instead of - ``True`` to customize the message. - :param prompt_required: If set to ``False``, the user will be - prompted for input only when the option was specified as a flag - without a value. - :param hide_input: If this is ``True`` then the input on the prompt - will be hidden from the user. This is useful for password input. - :param is_flag: forces this option to act as a flag. The default is - auto detection. - :param flag_value: which value should be used for this flag if it's - enabled. This is set to a boolean automatically if - the option string contains a slash to mark two options. - :param multiple: if this is set to `True` then the argument is accepted - multiple times and recorded. This is similar to ``nargs`` - in how it works but supports arbitrary number of - arguments. - :param count: this flag makes an option increment an integer. - :param allow_from_autoenv: if this is enabled then the value of this - parameter will be pulled from an environment - variable in case a prefix is defined on the - context. - :param help: the help string. - :param hidden: hide this option from help outputs. - :param attrs: Other command arguments described in :class:`Parameter`. - - .. versionchanged:: 8.4.0 - Non-basic ``flag_value`` types (not ``str``, ``int``, ``float``, or - ``bool``) are passed through unchanged instead of being stringified. - Previously, ``type=click.UNPROCESSED`` was required to preserve them. - - .. versionchanged:: 8.2 - ``envvar`` used with ``flag_value`` will always use the ``flag_value``, - previously it would use the value of the environment variable. - - .. versionchanged:: 8.1 - Help text indentation is cleaned here instead of only in the - ``@option`` decorator. - - .. versionchanged:: 8.1 - The ``show_default`` parameter overrides - ``Context.show_default``. - - .. versionchanged:: 8.1 - The default of a single option boolean flag is not shown if the - default value is ``False``. - - .. versionchanged:: 8.0.1 - ``type`` is detected from ``flag_value`` if given, for basic Python - types (``str``, ``int``, ``float``, ``bool``). - """ - - param_type_name = "option" - - def __init__( - self, - param_decls: cabc.Sequence[str] | None = None, - show_default: bool | str | None = None, - prompt: bool | str = False, - confirmation_prompt: bool | str = False, - prompt_required: bool = True, - hide_input: bool = False, - is_flag: bool | None = None, - flag_value: t.Any = UNSET, - multiple: bool = False, - count: bool = False, - allow_from_autoenv: bool = True, - type: types.ParamType[t.Any] | t.Any | None = None, - help: str | None = None, - hidden: bool = False, - show_choices: bool = True, - show_envvar: bool = False, - deprecated: bool | str = False, - **attrs: t.Any, - ) -> None: - if help: - help = inspect.cleandoc(help) - - super().__init__( - param_decls, type=type, multiple=multiple, deprecated=deprecated, **attrs - ) - - if prompt is True: - if not self.name: - raise TypeError("'name' is required with 'prompt=True'.") - - prompt_text: str | None = self.name.replace("_", " ").capitalize() - elif prompt is False: - prompt_text = None - else: - prompt_text = prompt - - if deprecated: - label = _format_deprecated_label(deprecated) - help = f"{help} {label}" if help is not None else label - - self.prompt = prompt_text - self.confirmation_prompt = confirmation_prompt - self.prompt_required = prompt_required - self.hide_input = hide_input - self.hidden = hidden - - # The _flag_needs_value property tells the parser that this option is a flag - # that cannot be used standalone and needs a value. With this information, the - # parser can determine whether to consider the next user-provided argument in - # the CLI as a value for this flag or as a new option. - # If prompt is enabled but not required, then it opens the possibility for the - # option to gets its value from the user. - self._flag_needs_value = self.prompt is not None and not self.prompt_required - - # Auto-detect if this is a flag or not. - if is_flag is None: - # Implicitly a flag because flag_value was set. - if flag_value is not UNSET: - is_flag = True - # Not a flag, but when used as a flag it shows a prompt. - elif self._flag_needs_value: - is_flag = False - # Implicitly a flag because secondary options names were given. - elif self.secondary_opts: - is_flag = True - - # The option is explicitly not a flag, but to determine whether or not it needs - # value, we need to check if `flag_value` or `default` was set. Either one is - # sufficient. - # Ref: https://github.com/pallets/click/issues/3084 - elif is_flag is False and not self._flag_needs_value: - self._flag_needs_value = flag_value is not UNSET or self.default is UNSET - - if is_flag: - # Set missing default for flags if not explicitly required or prompted. - if self.default is UNSET and not self.required and not self.prompt: - if multiple: - self.default = () - - # Auto-detect the type of the flag based on the flag_value. - if type is None: - # A flag without a flag_value is a boolean flag. - if flag_value is UNSET: - self.type: types.ParamType[t.Any] = types.BoolParamType() - # If the flag value is a boolean, use BoolParamType. - elif isinstance(flag_value, bool): - self.type = types.BoolParamType() - # Otherwise, guess the type from the flag value. - else: - guessed = types.convert_type(None, flag_value) - if ( - isinstance(guessed, types.StringParamType) - and not isinstance(flag_value, str) - and flag_value is not None - ): - # The flag_value type couldn't be auto-detected - # (not str, int, float, or bool). Since flag_value - # is a programmer-provided Python object, not CLI - # input, pass it through unchanged instead of - # stringifying it. - self.type = types.UNPROCESSED - else: - self.type = guessed - - self.is_flag: bool = bool(is_flag) - self.is_bool_flag: bool = bool( - is_flag and isinstance(self.type, types.BoolParamType) - ) - self.flag_value: t.Any = flag_value - - # Set boolean flag default to False if unset and not required. - if self.is_bool_flag: - if self.default is UNSET and not self.required: - self.default = False - - # The alignment of default to the flag_value is resolved lazily in - # get_default() to prevent callable flag_values (like classes) from - # being instantiated. Refs: - # https://github.com/pallets/click/issues/3121 - # https://github.com/pallets/click/issues/3024#issuecomment-3146199461 - # https://github.com/pallets/click/pull/3030/commits/06847da - - # Set the default flag_value if it is not set. - if self.flag_value is UNSET: - if self.is_flag: - self.flag_value = True - else: - self.flag_value = None - - # Counting. - self.count = count - if count: - if type is None: - self.type = types.IntRange(min=0) - if self.default is UNSET: - self.default = 0 - - self.allow_from_autoenv = allow_from_autoenv - self.help = help - self.show_default = show_default - self.show_choices = show_choices - self.show_envvar = show_envvar - - if __debug__: - if deprecated and prompt: - raise ValueError("`deprecated` options cannot use `prompt`.") - - if self.nargs == -1: - raise TypeError("nargs=-1 is not supported for options.") - - if not self.is_bool_flag and self.secondary_opts: - raise TypeError("Secondary flag is not valid for non-boolean flag.") - - if self.is_bool_flag and self.hide_input and self.prompt is not None: - raise TypeError( - "'prompt' with 'hide_input' is not valid for boolean flag." - ) - - if self.count: - if self.multiple: - raise TypeError("'count' is not valid with 'multiple'.") - - if self.is_flag: - raise TypeError("'count' is not valid with 'is_flag'.") - - def to_info_dict(self) -> dict[str, t.Any]: - """ - .. versionchanged:: 8.3.0 - Returns ``None`` for the :attr:`flag_value` if it was not set. - """ - info_dict = super().to_info_dict() - info_dict.update( - help=self.help, - prompt=self.prompt, - is_flag=self.is_flag, - # We explicitly hide the :attr:`UNSET` value to the user, as we choose to - # make it an implementation detail. And because ``to_info_dict`` has been - # designed for documentation purposes, we return ``None`` instead. - flag_value=self.flag_value if self.flag_value is not UNSET else None, - count=self.count, - hidden=self.hidden, - ) - return info_dict - - def get_default( - self, ctx: Context, call: bool = True - ) -> t.Any | t.Callable[[], t.Any] | None: - """Return the default value for this option. - - For non-boolean flag options, ``default=True`` is treated as a sentinel - meaning "activate this flag by default" and is resolved to - :attr:`flag_value`. For example, with ``--upper/--lower`` feature - switches where ``flag_value="upper"`` and ``default=True``, the default - resolves to ``"upper"``. - - .. caution:: - This substitution only applies to non-boolean flags - (:attr:`is_bool_flag` is ``False``). For boolean flags, ``True`` is - a legitimate Python value and ``default=True`` is returned as-is. - - .. versionchanged:: 8.3.3 - ``default=True`` is no longer substituted with ``flag_value`` for - boolean flags, fixing negative boolean flags like - ``flag_value=False, default=True``. - """ - value = super().get_default(ctx, call=False) - - # Resolve default=True to flag_value lazily (here instead of - # __init__) to prevent callable flag_values (like classes) from - # being instantiated by the callable check below. - if value is True and self.is_flag and not self.is_bool_flag: - value = self.flag_value - elif call and callable(value): - value = value() - - return value - - def get_error_hint(self, ctx: Context | None) -> str: - result = super().get_error_hint(ctx) - if self.show_envvar and self.envvar is not None: - result += f" (env var: '{self.envvar}')" - return result - - def _parse_decls( - self, decls: cabc.Sequence[str], expose_value: bool - ) -> tuple[str, list[str], list[str]]: - opts = [] - secondary_opts = [] - name = None - possible_names = [] - - for decl in decls: - if decl.isidentifier(): - if name is not None: - raise TypeError(_("Name '{name}' defined twice").format(name=name)) - 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( - _( - "Boolean option {decl!r} cannot use the" - " same flag for true/false." - ).format(decl=decl) - ) - 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 "", opts, secondary_opts - raise TypeError( - _( - "Could not determine name for option with declarations {decls!r}" - ).format(decls=decls) - ) - - if not opts and not secondary_opts: - raise TypeError( - _( - "No options defined but a name was passed ({name})." - " Did you mean to declare an argument instead? Did" - " you mean to pass '--{name}'?" - ).format(name=name) - ) - - return name, opts, secondary_opts - - def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: - if self.multiple: - action = "append" - elif self.count: - action = "count" - else: - action = "store" - - if self.is_flag: - action = f"{action}_const" - - if self.is_bool_flag and self.secondary_opts: - parser.add_option( - obj=self, opts=self.opts, dest=self.name, action=action, const=True - ) - parser.add_option( - obj=self, - opts=self.secondary_opts, - dest=self.name, - action=action, - const=False, - ) - else: - parser.add_option( - obj=self, - opts=self.opts, - dest=self.name, - action=action, - const=self.flag_value, - ) - else: - parser.add_option( - obj=self, - opts=self.opts, - dest=self.name, - action=action, - nargs=self.nargs, - ) - - def get_help_record(self, ctx: Context) -> tuple[str, str] | None: - if self.hidden: - return None - - any_prefix_is_slash = False - - def _write_opts(opts: cabc.Sequence[str]) -> str: - nonlocal any_prefix_is_slash - - rv, any_slashes = join_options(opts) - - if any_slashes: - any_prefix_is_slash = True - - if not self.is_flag and not self.count: - rv += f" {self.make_metavar(ctx=ctx)}" - - return rv - - rv = [_write_opts(self.opts)] - - if self.secondary_opts: - rv.append(_write_opts(self.secondary_opts)) - - help = self.help or "" - - extra = self.get_help_extra(ctx) - extra_items = [] - if "envvars" in extra: - extra_items.append( - _("env var: {var}").format(var=", ".join(extra["envvars"])) - ) - if "default" in extra: - extra_items.append(_("default: {default}").format(default=extra["default"])) - if "range" in extra: - extra_items.append(extra["range"]) - if "required" in extra: - extra_items.append(_(extra["required"])) - - if extra_items: - extra_str = "; ".join(extra_items) - help = f"{help} [{extra_str}]" if help else f"[{extra_str}]" - - return ("; " if any_prefix_is_slash else " / ").join(rv), help - - def get_help_extra(self, ctx: Context) -> types.OptionHelpExtra: - extra: types.OptionHelpExtra = {} - - if self.show_envvar: - envvar = self.envvar - - if envvar is None: - if ( - self.allow_from_autoenv - and ctx.auto_envvar_prefix is not None - and self.name - ): - envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" - - if envvar is not None: - if isinstance(envvar, str): - extra["envvars"] = (envvar,) - else: - extra["envvars"] = tuple(str(d) for d in envvar) - - # Temporarily enable resilient parsing to avoid type casting - # failing for the default. Might be possible to extend this to - # help formatting in general. - resilient = ctx.resilient_parsing - ctx.resilient_parsing = True - - try: - default_value = self.get_default(ctx, call=False) - finally: - ctx.resilient_parsing = resilient - - show_default = False - show_default_is_str = False - - if self.show_default is not None: - if isinstance(self.show_default, str): - show_default_is_str = show_default = True - else: - show_default = self.show_default - elif ctx.show_default is not None: - show_default = ctx.show_default - - if show_default_is_str or ( - show_default and (default_value not in (None, UNSET)) - ): - 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 isinstance(default_value, enum.Enum): - default_string = default_value.name - elif inspect.isfunction(default_value): - default_string = _("(dynamic)") - elif self.is_bool_flag and self.secondary_opts: - # For boolean flags that have distinct True/False opts, - # use the opt without prefix instead of the value. - default_string = _split_opt( - (self.opts if default_value else self.secondary_opts)[0] - )[1] - elif self.is_bool_flag and not self.secondary_opts and not default_value: - default_string = "" - elif isinstance(default_value, str) and default_value == "": - default_string = '""' - else: - default_string = str(default_value) - - if default_string: - extra["default"] = default_string - - if ( - isinstance(self.type, types._NumberRangeBase) - # skip count with default range type - and not (self.count and self.type.min == 0 and self.type.max is None) - ): - range_str = self.type._describe_range() - - if range_str: - extra["range"] = range_str - - if self.required: - extra["required"] = "required" - - return extra - - 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 lock in the value before - # attempting any user interaction. - default = self.get_default(ctx) - - # A boolean flag can use a simplified [y/n] confirmation prompt. - if self.is_bool_flag: - # If we have no boolean default, we force the user to explicitly provide - # one. - if default in (UNSET, None): - default = None - # Nothing prevent you to declare an option that is simultaneously: - # 1) auto-detected as a boolean flag, - # 2) allowed to prompt, and - # 3) still declare a non-boolean default. - # This forced casting into a boolean is necessary to align any non-boolean - # default to the prompt, which is going to be a [y/n]-style confirmation - # because the option is still a boolean flag. That way, instead of [y/n], - # we get [Y/n] or [y/N] depending on the truthy value of the default. - # Refs: https://github.com/pallets/click/pull/3030#discussion_r2289180249 - else: - default = bool(default) - return confirm(self.prompt, default) - - # If show_default is given, provide this to `prompt` as well, - # otherwise we use `prompt`'s default behavior - prompt_kwargs: t.Any = {} - if self.show_default is not None: - prompt_kwargs["show_default"] = self.show_default - - return prompt( - self.prompt, - # Use ``None`` to inform the prompt() function to reiterate until a valid - # value is provided by the user if we have no default. - default=None if default is UNSET else default, - type=self.type, - hide_input=self.hide_input, - show_choices=self.show_choices, - confirmation_prompt=self.confirmation_prompt, - value_proc=lambda x: self.process_value(ctx, x), - **prompt_kwargs, - ) - - def resolve_envvar_value(self, ctx: Context) -> str | None: - """:class:`Option` resolves its environment variable the same way as - :func:`Parameter.resolve_envvar_value`, but it also supports - :attr:`Context.auto_envvar_prefix`. If we could not find an environment from - the :attr:`envvar` property, we fallback on :attr:`Context.auto_envvar_prefix` - to build dynamiccaly the environment variable name using the - :python:`{ctx.auto_envvar_prefix}_{self.name.upper()}` template. - - :meta private: - """ - 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: - envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" - rv = os.environ.get(envvar) - - if rv: - return rv - - return None - - def value_from_envvar(self, ctx: Context) -> t.Any: - """For :class:`Option`, this method processes the raw environment variable - string the same way as :func:`Parameter.value_from_envvar` does. - - But in the case of non-boolean flags, the value is analyzed to determine if the - flag is activated or not, and returns a boolean of its activation, or the - :attr:`flag_value` if the latter is set. - - This method also takes care of repeated options (i.e. options with - :attr:`multiple` set to ``True``). - - :meta private: - """ - rv = self.resolve_envvar_value(ctx) - - # Absent environment variable or an empty string is interpreted as unset. - if rv is None: - return None - - # Non-boolean flags are more liberal in what they accept. But a flag being a - # flag, its envvar value still needs to be analyzed to determine if the flag is - # activated or not. - if self.is_flag and not self.is_bool_flag: - # If the flag_value is set and match the envvar value, return it - # directly. - if self.flag_value is not UNSET and rv == self.flag_value: - return self.flag_value - # Analyze the envvar value as a boolean to know if the flag is - # activated or not. - return types.BoolParamType.str_to_bool(rv) - - # Split the envvar value if it is allowed to be repeated. - value_depth = (self.nargs != 1) + bool(self.multiple) - if value_depth > 0: - multi_rv = self.type.split_envvar_value(rv) - if self.multiple and self.nargs != 1: - multi_rv = batch(multi_rv, self.nargs) # type: ignore[assignment] - - return multi_rv - - return rv - - def consume_value( - self, ctx: Context, opts: cabc.Mapping[str, Parameter] - ) -> tuple[t.Any, ParameterSource]: - """For :class:`Option`, the value can be collected from an interactive prompt - if the option is a flag that needs a value (and the :attr:`prompt` property is - set). - - Additionally, this method handles flag option that are activated without a - value, in which case the :attr:`flag_value` is returned. - - :meta private: - """ - value, source = super().consume_value(ctx, opts) - - # The parser will emit a sentinel value if the option is allowed to as a flag - # without a value. - if value is FLAG_NEEDS_VALUE: - # If the option allows for a prompt, we start an interaction with the user. - if self.prompt is not None and not ctx.resilient_parsing: - value = self.prompt_for_value(ctx) - source = ParameterSource.PROMPT - # Else the flag takes its flag_value as value. - else: - value = self.flag_value - source = ParameterSource.COMMANDLINE - - # A flag which is activated always returns the flag value, unless the value - # comes from the explicitly sets default. - elif ( - self.is_flag - and value is True - and not self.is_bool_flag - and source < ParameterSource.DEFAULT_MAP - ): - value = self.flag_value - - # Re-interpret a multiple option which has been sent as-is by the parser. - # Here we replace each occurrence of value-less flags (marked by the - # FLAG_NEEDS_VALUE sentinel) with the flag_value. - elif ( - self.multiple - and value is not UNSET - and isinstance(value, cabc.Iterable) - and source < ParameterSource.DEFAULT_MAP - 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 for one to the user - # if prompting is enabled. - elif ( - (value is UNSET or source >= ParameterSource.DEFAULT_MAP) - 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 - - def process_value(self, ctx: Context, value: t.Any) -> t.Any: - # process_value has to be overridden on Options in order to capture - # `value == UNSET` cases before `type_cast_value()` gets called. - # - # Refs: - # https://github.com/pallets/click/issues/3069 - if self.is_flag and not self.required and self.is_bool_flag and value is UNSET: - value = False - - if self.callback is not None: - value = self.callback(ctx, self, value) - - return value - - # in the normal case, rely on Parameter.process_value - return super().process_value(ctx, value) - - -class Argument(Parameter): - """Arguments are positional parameters to a command. They generally - provide fewer features than options but can have infinite ``nargs`` - and are required by default. - - All parameters are passed onwards to the constructor of :class:`Parameter`. - """ - - param_type_name = "argument" - - def __init__( - self, - param_decls: cabc.Sequence[str], - required: bool | None = None, - **attrs: t.Any, - ) -> None: - # Auto-detect the requirement status of the argument if not explicitly set. - if required is None: - # The argument gets automatically required if it has no explicit default - # value set and is setup to match at least one value. - if attrs.get("default", UNSET) is UNSET: - required = attrs.get("nargs", 1) > 0 - # If the argument has a default value, it is not required. - else: - required = False - - if "multiple" in attrs: - raise TypeError("__init__() got an unexpected keyword argument 'multiple'.") - - super().__init__(param_decls, required=required, **attrs) - - @property - def human_readable_name(self) -> str: - if self.metavar is not None: - return self.metavar - return self.name.upper() - - def make_metavar(self, ctx: Context) -> str: - if self.metavar is not None: - return self.metavar - var = self.type.get_metavar(param=self, ctx=ctx) - if not var: - var = self.name.upper() - if self.deprecated: - var += "!" - if not self.required: - var = f"[{var}]" - if self.nargs != 1: - var += "..." - return var - - def _parse_decls( - self, decls: cabc.Sequence[str], expose_value: bool - ) -> tuple[str, list[str], list[str]]: - if not decls: - if not expose_value: - return "", [], [] - raise TypeError("Argument is marked as exposed, but does not have a name.") - if len(decls) == 1: - name = arg = decls[0] - name = name.replace("-", "_").lower() - else: - raise TypeError( - _( - "Arguments take exactly one parameter declaration, got" - " {length}: {decls}." - ).format(length=len(decls), decls=decls) - ) - return name, [arg], [] - - def get_usage_pieces(self, ctx: Context) -> list[str]: - return [self.make_metavar(ctx)] - - def get_error_hint(self, ctx: Context | None) -> str: - if ctx is not None: - return f"'{self.make_metavar(ctx)}'" - return f"'{self.human_readable_name}'" - - def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: - parser.add_argument(dest=self.name, nargs=self.nargs, obj=self) - - -def __getattr__(name: str) -> object: - import warnings - - if name == "BaseCommand": - warnings.warn( - "'BaseCommand' is deprecated and will be removed in Click 9.0. Use" - " 'Command' instead.", - DeprecationWarning, - stacklevel=2, - ) - return _BaseCommand - - if name == "MultiCommand": - warnings.warn( - "'MultiCommand' is deprecated and will be removed in Click 9.0. Use" - " 'Group' instead.", - DeprecationWarning, - stacklevel=2, - ) - return _MultiCommand - - raise AttributeError(name) diff --git a/server/venv/Lib/site-packages/click/decorators.py b/server/venv/Lib/site-packages/click/decorators.py deleted file mode 100644 index 14aee42..0000000 --- a/server/venv/Lib/site-packages/click/decorators.py +++ /dev/null @@ -1,551 +0,0 @@ -from __future__ import annotations - -import inspect -import typing as t -from functools import update_wrapper -from gettext import gettext as _ - -from .core import Argument -from .core import Command -from .core import Context -from .core import Group -from .core import Option -from .core import Parameter -from .globals import get_current_context -from .utils import echo - -if t.TYPE_CHECKING: - import typing_extensions as te - - P = te.ParamSpec("P") - -R = t.TypeVar("R") -T = t.TypeVar("T") -_AnyCallable = t.Callable[..., t.Any] -FC = t.TypeVar("FC", bound="_AnyCallable | Command") - - -def pass_context(f: t.Callable[te.Concatenate[Context, P], R]) -> t.Callable[P, R]: - """Marks a callback as wanting to receive the current context - object as first argument. - """ - - def new_func(*args: P.args, **kwargs: P.kwargs) -> R: - return f(get_current_context(), *args, **kwargs) - - return update_wrapper(new_func, f) - - -def pass_obj(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: - """Similar to :func:`pass_context`, but only pass the object on the - context onwards (:attr:`Context.obj`). This is useful if that object - represents the state of a nested system. - """ - - def new_func(*args: P.args, **kwargs: P.kwargs) -> R: - return f(get_current_context().obj, *args, **kwargs) - - return update_wrapper(new_func, f) - - -def make_pass_decorator( - object_type: type[T], ensure: bool = False -) -> t.Callable[[t.Callable[te.Concatenate[T, P], R]], t.Callable[P, R]]: - """Given an object type this creates a decorator that will work - similar to :func:`pass_obj` but instead of passing the object of the - current context, it will find the innermost context of type - :func:`object_type`. - - This generates a decorator that works roughly like this:: - - from functools import update_wrapper - - def decorator(f): - @pass_context - def new_func(ctx, *args, **kwargs): - obj = ctx.find_object(object_type) - return ctx.invoke(f, obj, *args, **kwargs) - return update_wrapper(new_func, f) - return decorator - - :param object_type: the type of the object to pass. - :param ensure: if set to `True`, a new object will be created and - remembered on the context if it's not there yet. - """ - - def decorator(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: - def new_func(*args: P.args, **kwargs: P.kwargs) -> R: - ctx = get_current_context() - - obj: T | None - if ensure: - obj = ctx.ensure_object(object_type) - else: - obj = ctx.find_object(object_type) - - if obj is None: - raise RuntimeError( - "Managed to invoke callback without a context" - f" object of type {object_type.__name__!r}" - " existing." - ) - - return ctx.invoke(f, obj, *args, **kwargs) - - return update_wrapper(new_func, f) - - return decorator - - -def pass_meta_key( - key: str, *, doc_description: str | None = None -) -> t.Callable[[t.Callable[te.Concatenate[T, P], R]], t.Callable[P, R]]: - """Create a decorator that passes a key from - :attr:`click.Context.meta` as the first argument to the decorated - function. - - :param key: Key in ``Context.meta`` to pass. - :param doc_description: Description of the object being passed, - inserted into the decorator's docstring. Defaults to "the 'key' - key from Context.meta". - - .. versionadded:: 8.0 - """ - - def decorator(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: - def new_func(*args: P.args, **kwargs: P.kwargs) -> R: - ctx = get_current_context() - obj = ctx.meta[key] - return ctx.invoke(f, obj, *args, **kwargs) - - return update_wrapper(new_func, f) - - if doc_description is None: - doc_description = f"the {key!r} key from :attr:`click.Context.meta`" - - decorator.__doc__ = ( - f"Decorator that passes {doc_description} as the first argument" - " to the decorated function." - ) - return decorator - - -CmdType = t.TypeVar("CmdType", bound=Command) - - -# variant: no call, directly as decorator for a function. -@t.overload -def command(name: _AnyCallable) -> Command: ... - - -# variant: with positional name and with positional or keyword cls argument: -# @command(namearg, CommandCls, ...) or @command(namearg, cls=CommandCls, ...) -@t.overload -def command( - name: str | None, - cls: type[CmdType], - **attrs: t.Any, -) -> t.Callable[[_AnyCallable], CmdType]: ... - - -# variant: name omitted, cls _must_ be a keyword argument, @command(cls=CommandCls, ...) -@t.overload -def command( - name: None = None, - *, - cls: type[CmdType], - **attrs: t.Any, -) -> t.Callable[[_AnyCallable], CmdType]: ... - - -# variant: with optional string name, no cls argument provided. -@t.overload -def command( - name: str | None = ..., cls: None = None, **attrs: t.Any -) -> t.Callable[[_AnyCallable], Command]: ... - - -def command( - name: str | _AnyCallable | None = None, - cls: type[CmdType] | None = None, - **attrs: t.Any, -) -> Command | t.Callable[[_AnyCallable], Command | CmdType]: - r"""Creates a new :class:`Command` and uses the decorated function as - callback. This will also automatically attach all decorated - :func:`option`\s and :func:`argument`\s as parameters to the command. - - The name of the command defaults to the name of the function, converted to - lowercase, with underscores ``_`` replaced by dashes ``-``, and the suffixes - ``_command``, ``_cmd``, ``_group``, and ``_grp`` are removed. For example, - ``init_data_command`` becomes ``init-data``. - - All keyword arguments are forwarded to the underlying command class. - For the ``params`` argument, any decorated params are appended to - the end of the list. - - Once decorated the function turns into a :class:`Command` instance - that can be invoked as a command line utility or be attached to a - command :class:`Group`. - - :param name: The name of the command. Defaults to modifying the function's - name as described above. - :param cls: The command class to create. Defaults to :class:`Command`. - - .. versionchanged:: 8.2 - The suffixes ``_command``, ``_cmd``, ``_group``, and ``_grp`` are - removed when generating the name. - - .. versionchanged:: 8.1 - This decorator can be applied without parentheses. - - .. versionchanged:: 8.1 - The ``params`` argument can be used. Decorated params are - appended to the end of the list. - """ - - func: t.Callable[[_AnyCallable], t.Any] | None = None - - if callable(name): - func = name - name = None - assert cls is None, "Use 'command(cls=cls)(callable)' to specify a class." - assert not attrs, "Use 'command(**kwargs)(callable)' to provide arguments." - - if cls is None: - cls = t.cast("type[CmdType]", Command) - - def decorator(f: _AnyCallable) -> CmdType: - if isinstance(f, Command): - raise TypeError("Attempted to convert a callback into a command twice.") - - attr_params = attrs.pop("params", None) - params = attr_params if attr_params is not None else [] - - try: - decorator_params = f.__click_params__ # type: ignore - except AttributeError: - pass - else: - del f.__click_params__ # type: ignore - params.extend(reversed(decorator_params)) - - if attrs.get("help") is None: - attrs["help"] = f.__doc__ - - if t.TYPE_CHECKING: - assert cls is not None - assert not callable(name) - - if name is not None: - cmd_name = name - else: - cmd_name = f.__name__.lower().replace("_", "-") - cmd_left, sep, suffix = cmd_name.rpartition("-") - - if sep and suffix in {"command", "cmd", "group", "grp"}: - cmd_name = cmd_left - - cmd = cls(name=cmd_name, callback=f, params=params, **attrs) - cmd.__doc__ = f.__doc__ - return cmd - - if func is not None: - return decorator(func) - - return decorator - - -GrpType = t.TypeVar("GrpType", bound=Group) - - -# variant: no call, directly as decorator for a function. -@t.overload -def group(name: _AnyCallable) -> Group: ... - - -# variant: with positional name and with positional or keyword cls argument: -# @group(namearg, GroupCls, ...) or @group(namearg, cls=GroupCls, ...) -@t.overload -def group( - name: str | None, - cls: type[GrpType], - **attrs: t.Any, -) -> t.Callable[[_AnyCallable], GrpType]: ... - - -# variant: name omitted, cls _must_ be a keyword argument, @group(cmd=GroupCls, ...) -@t.overload -def group( - name: None = None, - *, - cls: type[GrpType], - **attrs: t.Any, -) -> t.Callable[[_AnyCallable], GrpType]: ... - - -# variant: with optional string name, no cls argument provided. -@t.overload -def group( - name: str | None = ..., cls: None = None, **attrs: t.Any -) -> t.Callable[[_AnyCallable], Group]: ... - - -def group( - name: str | _AnyCallable | None = None, - cls: type[GrpType] | None = None, - **attrs: t.Any, -) -> Group | t.Callable[[_AnyCallable], Group | GrpType]: - """Creates a new :class:`Group` with a function as callback. This - works otherwise the same as :func:`command` just that the `cls` - parameter is set to :class:`Group`. - - .. versionchanged:: 8.1 - This decorator can be applied without parentheses. - """ - if cls is None: - cls = t.cast("type[GrpType]", Group) - - if callable(name): - return command(cls=cls, **attrs)(name) - - return command(name, cls, **attrs) - - -def _param_memo(f: t.Callable[..., t.Any], param: Parameter) -> None: - if isinstance(f, Command): - f.params.append(param) - else: - if not hasattr(f, "__click_params__"): - f.__click_params__ = [] # type: ignore - - f.__click_params__.append(param) # type: ignore - - -def argument( - *param_decls: str, cls: type[Argument] | None = None, **attrs: t.Any -) -> t.Callable[[FC], FC]: - """Attaches an argument to the command. All positional arguments are - passed as parameter declarations to :class:`Argument`; all keyword - arguments are forwarded unchanged (except ``cls``). - This is equivalent to creating an :class:`Argument` instance manually - and attaching it to the :attr:`Command.params` list. - - For the default argument class, refer to :class:`Argument` and - :class:`Parameter` for descriptions of parameters. - - :param cls: the argument class to instantiate. This defaults to - :class:`Argument`. - :param param_decls: Passed as positional arguments to the constructor of - ``cls``. - :param attrs: Passed as keyword arguments to the constructor of ``cls``. - """ - if cls is None: - cls = Argument - - def decorator(f: FC) -> FC: - _param_memo(f, cls(param_decls, **attrs)) - return f - - return decorator - - -def option( - *param_decls: str, cls: type[Option] | None = None, **attrs: t.Any -) -> t.Callable[[FC], FC]: - """Attaches an option to the command. All positional arguments are - passed as parameter declarations to :class:`Option`; all keyword - arguments are forwarded unchanged (except ``cls``). - This is equivalent to creating an :class:`Option` instance manually - and attaching it to the :attr:`Command.params` list. - - For the default option class, refer to :class:`Option` and - :class:`Parameter` for descriptions of parameters. - - :param cls: the option class to instantiate. This defaults to - :class:`Option`. - :param param_decls: Passed as positional arguments to the constructor of - ``cls``. - :param attrs: Passed as keyword arguments to the constructor of ``cls``. - """ - if cls is None: - cls = Option - - def decorator(f: FC) -> FC: - _param_memo(f, cls(param_decls, **attrs)) - return f - - return decorator - - -def confirmation_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: - """Add a ``--yes`` option which shows a prompt before continuing if - not passed. If the prompt is declined, the program will exit. - - :param param_decls: One or more option names. Defaults to the single - value ``"--yes"``. - :param kwargs: Extra arguments are passed to :func:`option`. - """ - - def callback(ctx: Context, param: Parameter, value: bool) -> None: - if not value: - ctx.abort() - - if not param_decls: - param_decls = ("--yes",) - - kwargs.setdefault("is_flag", True) - kwargs.setdefault("callback", callback) - kwargs.setdefault("expose_value", False) - kwargs.setdefault("prompt", _("Do you want to continue?")) - kwargs.setdefault("help", _("Confirm the action without prompting.")) - return option(*param_decls, **kwargs) - - -def password_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: - """Add a ``--password`` option which prompts for a password, hiding - input and asking to enter the value again for confirmation. - - :param param_decls: One or more option names. Defaults to the single - value ``"--password"``. - :param kwargs: Extra arguments are passed to :func:`option`. - """ - if not param_decls: - param_decls = ("--password",) - - kwargs.setdefault("prompt", True) - kwargs.setdefault("confirmation_prompt", True) - kwargs.setdefault("hide_input", True) - return option(*param_decls, **kwargs) - - -def version_option( - version: str | None = None, - *param_decls: str, - package_name: str | None = None, - prog_name: str | None = None, - message: str | None = None, - **kwargs: t.Any, -) -> t.Callable[[FC], FC]: - """Add a ``--version`` option which immediately prints the version - number and exits the program. - - If ``version`` is not provided, Click will try to detect it using - :func:`importlib.metadata.version` to get the version for the - ``package_name``. - - If ``package_name`` is not provided, Click will try to detect it by - inspecting the stack frames. This will be used to detect the - version, so it must match the name of the installed package. - - :param version: The version number to show. If not provided, Click - will try to detect it. - :param param_decls: One or more option names. Defaults to the single - value ``"--version"``. - :param package_name: The package name to detect the version from. If - not provided, Click will try to detect it. - :param prog_name: The name of the CLI to show in the message. If not - provided, it will be detected from the command. - :param message: The message to show. The values ``%(prog)s``, - ``%(package)s``, and ``%(version)s`` are available. Defaults to - ``"%(prog)s, version %(version)s"``. - :param kwargs: Extra arguments are passed to :func:`option`. - :raise RuntimeError: ``version`` could not be detected. - - .. versionchanged:: 8.0 - Add the ``package_name`` parameter, and the ``%(package)s`` - value for messages. - - .. versionchanged:: 8.0 - Use :mod:`importlib.metadata` instead of ``pkg_resources``. The - version is detected based on the package name, not the entry - point name. The Python package name must match the installed - package name, or be passed with ``package_name=``. - """ - if message is None: - message = _("%(prog)s, version %(version)s") - - if version is None and package_name is None: - frame = inspect.currentframe() - f_back = frame.f_back if frame is not None else None - f_globals = f_back.f_globals if f_back is not None else None - # break reference cycle - # https://docs.python.org/3/library/inspect.html#the-interpreter-stack - del frame - - if f_globals is not None: - package_name = f_globals.get("__name__") - - if package_name == "__main__": - package_name = f_globals.get("__package__") - - if package_name: - package_name = package_name.partition(".")[0] - - def callback(ctx: Context, param: Parameter, value: bool) -> None: - if not value or ctx.resilient_parsing: - return - - nonlocal prog_name - nonlocal version - - if prog_name is None: - prog_name = ctx.find_root().info_name - - if version is None and package_name is not None: - import importlib.metadata - - try: - version = importlib.metadata.version(package_name) - except importlib.metadata.PackageNotFoundError: - raise RuntimeError( - f"{package_name!r} is not installed. Try passing" - " 'package_name' instead." - ) from None - - if version is None: - raise RuntimeError( - f"Could not determine the version for {package_name!r} automatically." - ) - - echo( - message % {"prog": prog_name, "package": package_name, "version": version}, - color=ctx.color, - ) - ctx.exit() - - if not param_decls: - param_decls = ("--version",) - - kwargs.setdefault("is_flag", True) - kwargs.setdefault("expose_value", False) - kwargs.setdefault("is_eager", True) - kwargs.setdefault("help", _("Show the version and exit.")) - kwargs["callback"] = callback - return option(*param_decls, **kwargs) - - -def help_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: - """Pre-configured ``--help`` option which immediately prints the help page - and exits the program. - - :param param_decls: One or more option names. Defaults to the single - value ``"--help"``. - :param kwargs: Extra arguments are passed to :func:`option`. - """ - - def show_help(ctx: Context, param: Parameter, value: bool) -> None: - """Callback that print the help page on ```` and exits.""" - if value and not ctx.resilient_parsing: - echo(ctx.get_help(), color=ctx.color) - ctx.exit() - - if not param_decls: - param_decls = ("--help",) - - kwargs.setdefault("is_flag", True) - kwargs.setdefault("expose_value", False) - kwargs.setdefault("is_eager", True) - kwargs.setdefault("help", _("Show this message and exit.")) - kwargs.setdefault("callback", show_help) - - return option(*param_decls, **kwargs) diff --git a/server/venv/Lib/site-packages/click/exceptions.py b/server/venv/Lib/site-packages/click/exceptions.py deleted file mode 100644 index 68c2806..0000000 --- a/server/venv/Lib/site-packages/click/exceptions.py +++ /dev/null @@ -1,347 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import typing as t -from gettext import gettext as _ -from gettext import ngettext - -from ._compat import get_text_stderr -from .globals import resolve_color_default -from .utils import echo -from .utils import format_filename - -if t.TYPE_CHECKING: - from .core import Command - from .core import Context - from .core import Parameter - - -def _join_param_hints(param_hint: cabc.Sequence[str] | str | None) -> str | None: - if param_hint is not None and not isinstance(param_hint, str): - return " / ".join(repr(x) for x in param_hint) - - return param_hint - - -def _format_possibilities(possibilities: list[str]) -> str: - possibility_str = ", ".join(repr(p) for p in sorted(possibilities)) - return ngettext( - "Did you mean {possibility}?", - "(Did you mean one of: {possibilities}?)", - len(possibilities), - ).format(possibility=possibility_str, possibilities=possibility_str) - - -class ClickException(Exception): - """An exception that Click can handle and show to the user.""" - - #: The exit code for this exception. - exit_code = 1 - - def __init__(self, message: str) -> None: - super().__init__(message) - # The context will be removed by the time we print the message, so cache - # the color settings here to be used later on (in `show`) - self.show_color: bool | None = resolve_color_default() - self.message = message - - def format_message(self) -> str: - return self.message - - def __str__(self) -> str: - return self.message - - def show(self, file: t.IO[t.Any] | None = None) -> None: - if file is None: - file = get_text_stderr() - - echo( - _("Error: {message}").format(message=self.format_message()), - file=file, - color=self.show_color, - ) - - -class UsageError(ClickException): - """An internal exception that signals a usage error. This typically - aborts any further handling. - - :param message: the error message to display. - :param ctx: optionally the context that caused this error. Click will - fill in the context automatically in some situations. - """ - - exit_code = 2 - - def __init__(self, message: str, ctx: Context | None = None) -> None: - super().__init__(message) - self.ctx = ctx - self.cmd: Command | None = self.ctx.command if self.ctx else None - - def show(self, file: t.IO[t.Any] | None = None) -> None: - if file is None: - file = get_text_stderr() - color = None - hint = "" - if ( - self.ctx is not None - and self.ctx.command.get_help_option(self.ctx) is not None - ): - help_names = self.ctx.command.get_help_option_names(self.ctx) - # Pick the longest name (like ``--help`` over ``-h``) for - # readability in error messages. - hint = _("Try '{command} {option}' for help.").format( - command=self.ctx.command_path, - option=max(help_names, key=len), - ) - hint = f"{hint}\n" - if self.ctx is not None: - color = self.ctx.color - echo(f"{self.ctx.get_usage()}\n{hint}", file=file, color=color) - echo( - _("Error: {message}").format(message=self.format_message()), - file=file, - color=color, - ) - - -class BadParameter(UsageError): - """An exception that formats out a standardized error message for a - bad parameter. This is useful when thrown from a callback or type as - Click will attach contextual information to it (for instance, which - parameter it is). - - .. versionadded:: 2.0 - - :param param: the parameter object that caused this error. This can - be left out, and Click will attach this info itself - if possible. - :param param_hint: a string that shows up as parameter name. This - can be used as alternative to `param` in cases - where custom validation should happen. If it is - a string it's used as such, if it's a list then - each item is quoted and separated. - """ - - def __init__( - self, - message: str, - ctx: Context | None = None, - param: Parameter | None = None, - param_hint: cabc.Sequence[str] | str | None = None, - ) -> None: - super().__init__(message, ctx) - self.param = param - self.param_hint = param_hint - - def format_message(self) -> str: - if self.param_hint is not None: - param_hint = self.param_hint - elif self.param is not None: - param_hint = self.param.get_error_hint(self.ctx) - else: - return _("Invalid value: {message}").format(message=self.message) - - return _("Invalid value for {param_hint}: {message}").format( - param_hint=_join_param_hints(param_hint), message=self.message - ) - - -class MissingParameter(BadParameter): - """Raised if click required an option or argument but it was not - provided when invoking the script. - - .. versionadded:: 4.0 - - :param param_type: a string that indicates the type of the parameter. - The default is to inherit the parameter type from - the given `param`. Valid values are ``'parameter'``, - ``'option'`` or ``'argument'``. - """ - - def __init__( - self, - message: str | None = None, - ctx: Context | None = None, - param: Parameter | None = None, - param_hint: cabc.Sequence[str] | str | None = None, - param_type: str | None = None, - ) -> None: - super().__init__(message or "", ctx, param, param_hint) - self.param_type = param_type - - def format_message(self) -> str: - if self.param_hint is not None: - param_hint: cabc.Sequence[str] | str | None = self.param_hint - elif self.param is not None: - param_hint = self.param.get_error_hint(self.ctx) - else: - param_hint = None - - param_hint = _join_param_hints(param_hint) - param_hint = f" {param_hint}" if param_hint else "" - - param_type = self.param_type - if param_type is None and self.param is not None: - param_type = self.param.param_type_name - - msg = self.message - if self.param is not None: - msg_extra = self.param.type.get_missing_message( - param=self.param, ctx=self.ctx - ) - if msg_extra: - if msg: - msg += f". {msg_extra}" - else: - msg = msg_extra - - msg = f" {msg}" if msg else "" - - # Translate param_type for known types. - if param_type == "argument": - missing = _("Missing argument") - elif param_type == "option": - missing = _("Missing option") - elif param_type == "parameter": - missing = _("Missing parameter") - else: - missing = _("Missing {param_type}").format(param_type=param_type) - - return f"{missing}{param_hint}.{msg}" - - def __str__(self) -> str: - if not self.message: - param_name = self.param.name if self.param else None - return _("Missing parameter: {param_name}").format(param_name=param_name) - else: - return self.message - - -class NoSuchOption(UsageError): - """Raised if Click attempted to handle an option that does not exist. - - .. versionadded:: 4.0 - """ - - def __init__( - self, - option_name: str, - message: str | None = None, - possibilities: cabc.Iterable[str] | None = None, - ctx: Context | None = None, - ) -> None: - if message is None: - message = _("No such option {name!r}.").format(name=option_name) - - super().__init__(message, ctx) - self.option_name = option_name - self.possibilities: list[str] | None = None - if possibilities: - from difflib import get_close_matches - - self.possibilities = get_close_matches(option_name, possibilities) - - def format_message(self) -> str: - if not self.possibilities: - return self.message - return f"{self.message} {_format_possibilities(self.possibilities)}" - - -class NoSuchCommand(UsageError): - """Raised if Click attempted to handle a command that does not exist. - - .. versionadded:: 8.4.0 - """ - - def __init__( - self, - command_name: str, - message: str | None = None, - possibilities: cabc.Iterable[str] | None = None, - ctx: Context | None = None, - ) -> None: - if message is None: - message = _("No such command {name!r}.").format(name=command_name) - - super().__init__(message, ctx) - self.command_name = command_name - self.possibilities: list[str] | None = None - if possibilities: - from difflib import get_close_matches - - self.possibilities = get_close_matches(command_name, possibilities) - - def format_message(self) -> str: - if not self.possibilities: - return self.message - return f"{self.message} {_format_possibilities(self.possibilities)}" - - -class BadOptionUsage(UsageError): - """Raised if an option is generally supplied but the use of the option - was incorrect. This is for instance raised if the number of arguments - for an option is not correct. - - .. versionadded:: 4.0 - - :param option_name: the name of the option being used incorrectly. - """ - - def __init__( - self, option_name: str, message: str, ctx: Context | None = None - ) -> None: - super().__init__(message, ctx) - self.option_name = option_name - - -class BadArgumentUsage(UsageError): - """Raised if an argument is generally supplied but the use of the argument - was incorrect. This is for instance raised if the number of values - for an argument is not correct. - - .. versionadded:: 6.0 - """ - - -class NoArgsIsHelpError(UsageError): - def __init__(self, ctx: Context) -> None: - self.ctx: Context - super().__init__(ctx.get_help(), ctx=ctx) - - def show(self, file: t.IO[t.Any] | None = None) -> None: - echo(self.format_message(), file=file, err=True, color=self.ctx.color) - - -class FileError(ClickException): - """Raised if a file cannot be opened.""" - - def __init__(self, filename: str, hint: str | None = None) -> None: - if hint is None: - hint = _("unknown error") - - super().__init__(hint) - self.ui_filename: str = format_filename(filename) - self.filename = filename - - def format_message(self) -> str: - return _("Could not open file {filename!r}: {message}").format( - filename=self.ui_filename, message=self.message - ) - - -class Abort(RuntimeError): - """An internal signalling exception that signals Click to abort.""" - - -class Exit(RuntimeError): - """An exception that indicates that the application should exit with some - status code. - - :param code: the status code to exit with. - """ - - __slots__ = ("exit_code",) - - def __init__(self, code: int = 0) -> None: - self.exit_code: int = code diff --git a/server/venv/Lib/site-packages/click/formatting.py b/server/venv/Lib/site-packages/click/formatting.py deleted file mode 100644 index 886a4ad..0000000 --- a/server/venv/Lib/site-packages/click/formatting.py +++ /dev/null @@ -1,315 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -from contextlib import contextmanager -from gettext import gettext as _ - -from ._compat import term_len -from .parser import _split_opt - -# Can force a width. This is used by the test system -FORCED_WIDTH: int | None = None - - -def measure_table(rows: cabc.Iterable[tuple[str, str]]) -> tuple[int, ...]: - widths: dict[int, int] = {} - - for row in rows: - for idx, col in enumerate(row): - widths[idx] = max(widths.get(idx, 0), term_len(col)) - - return tuple(y for x, y in sorted(widths.items())) - - -def iter_rows( - rows: cabc.Iterable[tuple[str, str]], col_count: int -) -> cabc.Iterator[tuple[str, ...]]: - for row in rows: - yield row + ("",) * (col_count - len(row)) - - -def wrap_text( - text: str, - width: int = 78, - initial_indent: str = "", - subsequent_indent: str = "", - preserve_paragraphs: bool = False, -) -> str: - """A helper function that intelligently wraps text. By default, it - assumes that it operates on a single paragraph of text but if the - `preserve_paragraphs` parameter is provided it will intelligently - handle paragraphs (defined by two empty lines). - - If paragraphs are handled, a paragraph can be prefixed with an empty - line containing the ``\\b`` character (``\\x08``) to indicate that - no rewrapping should happen in that block. - - :param text: the text that should be rewrapped. - :param width: the maximum width for the text. - :param initial_indent: the initial indent that should be placed on the - first line as a string. - :param subsequent_indent: the indent string that should be placed on - each consecutive line. - :param preserve_paragraphs: if this flag is set then the wrapping will - intelligently handle paragraphs. - - .. versionchanged:: 8.4.0 - Width is measured in visible characters. ANSI escape sequences in - ``text``, ``initial_indent``, or ``subsequent_indent`` no longer - count toward the width budget, so styled input wraps based on what - the user sees instead of raw byte length. - """ - from ._textwrap import TextWrapper - - text = text.expandtabs() - wrapper = TextWrapper( - width, - initial_indent=initial_indent, - subsequent_indent=subsequent_indent, - replace_whitespace=False, - ) - if not preserve_paragraphs: - return wrapper.fill(text) - - p: list[tuple[int, bool, str]] = [] - buf: list[str] = [] - indent = None - - def _flush_par() -> None: - if not buf: - return - if buf[0].strip() == "\b": - p.append((indent or 0, True, "\n".join(buf[1:]))) - else: - p.append((indent or 0, False, " ".join(buf))) - del buf[:] - - for line in text.splitlines(): - if not line: - _flush_par() - indent = None - else: - if indent is None: - orig_len = term_len(line) - line = line.lstrip() - indent = orig_len - term_len(line) - buf.append(line) - _flush_par() - - rv = [] - for indent, raw, text in p: - with wrapper.extra_indent(" " * indent): - if raw: - rv.append(wrapper.indent_only(text)) - else: - rv.append(wrapper.fill(text)) - - return "\n\n".join(rv) - - -class HelpFormatter: - """This class helps with formatting text-based help pages. It's - usually just needed for very special internal cases, but it's also - exposed so that developers can write their own fancy outputs. - - At present, it always writes into memory. - - :param indent_increment: the additional increment for each level. - :param width: the width for the text. This defaults to the terminal - width clamped to a maximum of 78. - """ - - def __init__( - self, - indent_increment: int = 2, - width: int | None = None, - max_width: int | None = None, - ) -> None: - self.indent_increment = indent_increment - if max_width is None: - max_width = 80 - if width is None: - import shutil - - width = FORCED_WIDTH - if width is None: - width = max(min(shutil.get_terminal_size().columns, max_width) - 2, 50) - self.width = width - self.current_indent: int = 0 - self.buffer: list[str] = [] - - def write(self, string: str) -> None: - """Writes a unicode string into the internal buffer.""" - self.buffer.append(string) - - def indent(self) -> None: - """Increases the indentation.""" - self.current_indent += self.indent_increment - - def dedent(self) -> None: - """Decreases the indentation.""" - self.current_indent -= self.indent_increment - - def write_usage(self, prog: str, args: str = "", prefix: str | None = None) -> None: - """Writes a usage line into the buffer. - - :param prog: the program name. - :param args: whitespace separated list of arguments. - :param prefix: The prefix for the first line. Defaults to - ``"Usage: "``. - """ - if prefix is None: - prefix = "{usage} ".format(usage=_("Usage:")) - - usage_prefix = f"{prefix:>{self.current_indent}}{prog} " - text_width = self.width - self.current_indent - - if not args: - # Without args, the prefix's trailing space and the wrap_text - # call that would normally place args on the line are both - # unnecessary. Emit just the prefix line. - self.write(usage_prefix.rstrip(" ")) - self.write("\n") - return - - if text_width >= (term_len(usage_prefix) + 20): - # The arguments will fit to the right of the prefix. - indent = " " * term_len(usage_prefix) - self.write( - wrap_text( - args, - text_width, - initial_indent=usage_prefix, - subsequent_indent=indent, - ) - ) - else: - # The prefix is too long, put the arguments on the next line. - self.write(usage_prefix) - self.write("\n") - indent = " " * (max(self.current_indent, term_len(prefix)) + 4) - self.write( - wrap_text( - args, text_width, initial_indent=indent, subsequent_indent=indent - ) - ) - - self.write("\n") - - def write_heading(self, heading: str) -> None: - """Writes a heading into the buffer.""" - self.write(f"{'':>{self.current_indent}}{heading}:\n") - - def write_paragraph(self) -> None: - """Writes a paragraph into the buffer.""" - if self.buffer: - self.write("\n") - - def write_text(self, text: str) -> None: - """Writes re-indented text into the buffer. This rewraps and - preserves paragraphs. - """ - indent = " " * self.current_indent - self.write( - wrap_text( - text, - self.width, - initial_indent=indent, - subsequent_indent=indent, - preserve_paragraphs=True, - ) - ) - self.write("\n") - - def write_dl( - self, - rows: cabc.Sequence[tuple[str, str]], - col_max: int = 30, - col_spacing: int = 2, - ) -> None: - """Writes a definition list into the buffer. This is how options - and commands are usually formatted. - - :param rows: a list of two item tuples for the terms and values. - :param col_max: the maximum width of the first column. - :param col_spacing: the number of spaces between the first and - second column. - """ - rows = list(rows) - widths = measure_table(rows) - if len(widths) != 2: - raise TypeError("Expected two columns for definition list") - - first_col = min(widths[0], col_max) + col_spacing - - for first, second in iter_rows(rows, len(widths)): - self.write(f"{'':>{self.current_indent}}{first}") - if not second: - self.write("\n") - continue - if term_len(first) <= first_col - col_spacing: - self.write(" " * (first_col - term_len(first))) - else: - self.write("\n") - self.write(" " * (first_col + self.current_indent)) - - text_width = max(self.width - first_col - 2, 10) - wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True) - lines = wrapped_text.splitlines() - - if lines: - self.write(f"{lines[0]}\n") - - for line in lines[1:]: - self.write(f"{'':>{first_col + self.current_indent}}{line}\n") - else: - self.write("\n") - - @contextmanager - def section(self, name: str) -> cabc.Iterator[None]: - """Helpful context manager that writes a paragraph, a heading, - and the indents. - - :param name: the section name that is written as heading. - """ - self.write_paragraph() - self.write_heading(name) - self.indent() - try: - yield - finally: - self.dedent() - - @contextmanager - def indentation(self) -> cabc.Iterator[None]: - """A context manager that increases the indentation.""" - self.indent() - try: - yield - finally: - self.dedent() - - def getvalue(self) -> str: - """Returns the buffer contents.""" - return "".join(self.buffer) - - -def join_options(options: cabc.Sequence[str]) -> tuple[str, bool]: - """Given a list of option strings this joins them in the most appropriate - way and returns them in the form ``(formatted_string, - any_prefix_is_slash)`` where the second item in the tuple is a flag that - indicates if any of the option prefixes was a slash. - """ - rv = [] - any_prefix_is_slash = False - - for opt in options: - prefix = _split_opt(opt)[0] - - if prefix == "/": - any_prefix_is_slash = True - - rv.append((len(prefix), opt)) - - rv.sort(key=lambda x: x[0]) - return ", ".join(x[1] for x in rv), any_prefix_is_slash diff --git a/server/venv/Lib/site-packages/click/globals.py b/server/venv/Lib/site-packages/click/globals.py deleted file mode 100644 index a2f9172..0000000 --- a/server/venv/Lib/site-packages/click/globals.py +++ /dev/null @@ -1,67 +0,0 @@ -from __future__ import annotations - -import typing as t -from threading import local - -if t.TYPE_CHECKING: - from .core import Context - -_local = local() - - -@t.overload -def get_current_context(silent: t.Literal[False] = False) -> Context: ... - - -@t.overload -def get_current_context(silent: bool = ...) -> Context | None: ... - - -def get_current_context(silent: bool = False) -> Context | None: - """Returns the current click context. This can be used as a way to - access the current context object from anywhere. This is a more implicit - alternative to the :func:`pass_context` decorator. This function is - primarily useful for helpers such as :func:`echo` which might be - interested in changing its behavior based on the current context. - - To push the current context, :meth:`Context.scope` can be used. - - .. versionadded:: 5.0 - - :param silent: if set to `True` the return value is `None` if no context - is available. The default behavior is to raise a - :exc:`RuntimeError`. - """ - try: - return t.cast("Context", _local.stack[-1]) - except (AttributeError, IndexError) as e: - if not silent: - raise RuntimeError("There is no active click context.") from e - - return None - - -def push_context(ctx: Context) -> None: - """Pushes a new context to the current stack.""" - _local.__dict__.setdefault("stack", []).append(ctx) - - -def pop_context() -> None: - """Removes the top level from the stack.""" - _local.stack.pop() - - -def resolve_color_default(color: bool | None = None) -> bool | None: - """Internal helper to get the default value of the color flag. If a - value is passed it's returned unchanged, otherwise it's looked up from - the current context. - """ - if color is not None: - return color - - ctx = get_current_context(silent=True) - - if ctx is not None: - return ctx.color - - return None diff --git a/server/venv/Lib/site-packages/click/parser.py b/server/venv/Lib/site-packages/click/parser.py deleted file mode 100644 index 4fcbf7c..0000000 --- a/server/venv/Lib/site-packages/click/parser.py +++ /dev/null @@ -1,533 +0,0 @@ -""" -This module started out as largely a copy paste from the stdlib's -optparse module with the features removed that we do not need from -optparse because we implement them in Click on a higher level (for -instance type handling, help formatting and a lot more). - -The plan is to remove more and more from here over time. - -The reason this is a different module and not optparse from the stdlib -is that there are differences in 2.x and 3.x about the error messages -generated and optparse in the stdlib uses gettext for no good reason -and might cause us issues. - -Click uses parts of optparse written by Gregory P. Ward and maintained -by the Python Software Foundation. This is limited to code in parser.py. - -Copyright 2001-2006 Gregory P. Ward. All rights reserved. -Copyright 2002-2006 Python Software Foundation. All rights reserved. -""" - -# This code uses parts of optparse written by Gregory P. Ward and -# maintained by the Python Software Foundation. -# Copyright 2001-2006 Gregory P. Ward -# Copyright 2002-2006 Python Software Foundation -from __future__ import annotations - -import collections.abc as cabc -import typing as t -from collections import deque -from gettext import gettext as _ -from gettext import ngettext - -from ._utils import FLAG_NEEDS_VALUE -from ._utils import UNSET -from .exceptions import BadArgumentUsage -from .exceptions import BadOptionUsage -from .exceptions import NoSuchOption -from .exceptions import UsageError - -if t.TYPE_CHECKING: - from ._utils import T_FLAG_NEEDS_VALUE - from ._utils import T_UNSET - 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") - - -def _unpack_args( - args: cabc.Sequence[str], nargs_spec: cabc.Sequence[int] -) -> tuple[cabc.Sequence[str | cabc.Sequence[str | T_UNSET] | T_UNSET], 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 ``UNSET``. - """ - args = deque(args) - nargs_spec = deque(nargs_spec) - rv: list[str | tuple[str | T_UNSET, ...] | T_UNSET] = [] - spos: int | None = None - - def _fetch(c: deque[str]) -> str | T_UNSET: - try: - if spos is None: - return c.popleft() - else: - return c.pop() - except IndexError: - return UNSET - - while nargs_spec: - if spos is None: - nargs = nargs_spec.popleft() - else: - nargs = nargs_spec.pop() - - if nargs == 1: - rv.append(_fetch(args)) - elif nargs > 1: - x: list[str | T_UNSET] = [_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(UNSET) - - # spos is the position of the wildcard (star). If it's not `None`, - # we fill it with the remainder. - if spos is not None: - rv[spos] = tuple(args) - args = [] - rv[spos + 1 :] = reversed(rv[spos + 1 :]) - - return tuple(rv), list(args) - - -def _split_opt(opt: str) -> tuple[str, str]: - first = opt[:1] - if first.isalnum(): - return "", opt - if opt[1:2] == first: - return opt[:2], opt[2:] - return first, opt[1:] - - -def _normalize_opt(opt: str, ctx: Context | None) -> str: - if ctx is None or ctx.token_normalize_func is None: - return opt - prefix, opt = _split_opt(opt) - return f"{prefix}{ctx.token_normalize_func(opt)}" - - -class _Option: - def __init__( - self, - obj: CoreOption, - opts: cabc.Sequence[str], - dest: str | None, - action: str | None = None, - nargs: int = 1, - const: t.Any | None = None, - ): - self._short_opts = [] - self._long_opts = [] - self.prefixes: set[str] = set() - - for opt in opts: - prefix, value = _split_opt(opt) - if not prefix: - raise ValueError( - _("Invalid start character for option ({option})").format( - option=opt - ) - ) - self.prefixes.add(prefix[0]) - if len(prefix) == 1 and len(value) == 1: - self._short_opts.append(opt) - else: - self._long_opts.append(opt) - self.prefixes.add(prefix) - - if action is None: - action = "store" - - self.dest = dest - self.action = action - self.nargs = nargs - self.const = const - self.obj = obj - - @property - def takes_value(self) -> bool: - return self.action in ("store", "append") - - def process(self, value: t.Any, state: _ParsingState) -> None: - if self.action == "store": - state.opts[self.dest] = value # type: ignore - elif self.action == "store_const": - state.opts[self.dest] = self.const # type: ignore - elif self.action == "append": - state.opts.setdefault(self.dest, []).append(value) # type: ignore - elif self.action == "append_const": - state.opts.setdefault(self.dest, []).append(self.const) # type: ignore - elif self.action == "count": - state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 # type: ignore - else: - raise ValueError(f"unknown action '{self.action}'") - state.order.append(self.obj) - - -class _Argument: - def __init__(self, obj: CoreArgument, dest: str | None, nargs: int = 1): - self.dest = dest - self.nargs = nargs - self.obj = obj - - def process( - self, - value: str | cabc.Sequence[str | T_UNSET] | T_UNSET, - state: _ParsingState, - ) -> None: - if self.nargs > 1: - assert isinstance(value, cabc.Sequence) - holes = sum(x is UNSET for x in value) - if holes == len(value): - value = UNSET - elif holes != 0: - raise BadArgumentUsage( - _("Argument {name!r} takes {nargs} values.").format( - name=self.dest, nargs=self.nargs - ) - ) - - # We failed to collect any argument value so we consider the argument as unset. - if value == (): - value = UNSET - - state.opts[self.dest] = value # type: ignore - state.order.append(self.obj) - - -class _ParsingState: - def __init__(self, rargs: list[str]) -> None: - self.opts: dict[str, t.Any] = {} - self.largs: list[str] = [] - self.rargs = rargs - self.order: list[CoreParameter] = [] - - -class _OptionParser: - """The option parser is an internal class that is ultimately used to - parse options and arguments. It's modelled after optparse and brings - a similar but vastly simplified API. It should generally not be used - directly as the high level Click classes wrap it for you. - - It's not nearly as extensible as optparse or argparse as it does not - implement features that are implemented on a higher level (such as - types or defaults). - - :param ctx: optionally the :class:`~click.Context` where this parser - should go with. - - .. deprecated:: 8.2 - Will be removed in Click 9.0. - """ - - def __init__(self, ctx: Context | None = None) -> None: - #: The :class:`~click.Context` for this parser. This might be - #: `None` for some advanced use cases. - self.ctx = ctx - #: This controls how the parser deals with interspersed arguments. - #: If this is set to `False`, the parser will stop on the first - #: non-option. Click uses this to implement nested subcommands - #: safely. - self.allow_interspersed_args: bool = True - #: This tells the parser how to deal with unknown options. By - #: default it will error out (which is sensible), but there is a - #: second mode where it will ignore it and continue processing - #: after shifting all the unknown options into the resulting args. - self.ignore_unknown_options: bool = False - - if ctx is not None: - self.allow_interspersed_args = ctx.allow_interspersed_args - self.ignore_unknown_options = ctx.ignore_unknown_options - - self._short_opt: dict[str, _Option] = {} - self._long_opt: dict[str, _Option] = {} - self._opt_prefixes = {"-", "--"} - self._args: list[_Argument] = [] - - def add_option( - self, - obj: CoreOption, - opts: cabc.Sequence[str], - dest: str | None, - action: str | None = None, - nargs: int = 1, - const: t.Any | None = None, - ) -> None: - """Adds a new option named `dest` to the parser. The destination - is not inferred (unlike with optparse) and needs to be explicitly - provided. Action can be any of ``store``, ``store_const``, - ``append``, ``append_const`` or ``count``. - - The `obj` can be used to identify the option in the order list - that is returned from the parser. - """ - opts = [_normalize_opt(opt, self.ctx) for opt in opts] - option = _Option(obj, opts, dest, action=action, nargs=nargs, const=const) - self._opt_prefixes.update(option.prefixes) - for opt in option._short_opts: - self._short_opt[opt] = option - for opt in option._long_opts: - self._long_opt[opt] = option - - def add_argument(self, obj: CoreArgument, dest: str | None, nargs: int = 1) -> None: - """Adds a positional argument named `dest` to the parser. - - The `obj` can be used to identify the option in the order list - that is returned from the parser. - """ - self._args.append(_Argument(obj, dest=dest, nargs=nargs)) - - def parse_args( - self, args: list[str] - ) -> tuple[dict[str, t.Any], list[str], list[CoreParameter]]: - """Parses positional arguments and returns ``(values, args, order)`` - for the parsed options and arguments as well as the leftover - arguments if there are any. The order is a list of objects as they - appear on the command line. If arguments appear multiple times they - will be memorized multiple times as well. - """ - state = _ParsingState(args) - try: - self._process_args_for_options(state) - self._process_args_for_args(state) - except UsageError: - if self.ctx is None or not self.ctx.resilient_parsing: - raise - return state.opts, state.largs, state.order - - def _process_args_for_args(self, state: _ParsingState) -> None: - pargs, args = _unpack_args( - state.largs + state.rargs, [x.nargs for x in self._args] - ) - - for idx, arg in enumerate(self._args): - arg.process(pargs[idx], state) - - state.largs = args - state.rargs = [] - - def _process_args_for_options(self, state: _ParsingState) -> None: - while state.rargs: - arg = state.rargs.pop(0) - arglen = len(arg) - # Double dashes always handled explicitly regardless of what - # prefixes are valid. - if arg == "--": - return - elif arg[:1] in self._opt_prefixes and arglen > 1: - self._process_opts(arg, state) - elif self.allow_interspersed_args: - state.largs.append(arg) - else: - state.rargs.insert(0, arg) - return - - # Say this is the original argument list: - # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] - # ^ - # (we are about to process arg(i)). - # - # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of - # [arg0, ..., arg(i-1)] (any options and their arguments will have - # been removed from largs). - # - # The while loop will usually consume 1 or more arguments per pass. - # If it consumes 1 (eg. arg is an option that takes no arguments), - # then after _process_arg() is done the situation is: - # - # largs = subset of [arg0, ..., arg(i)] - # rargs = [arg(i+1), ..., arg(N-1)] - # - # If allow_interspersed_args is false, largs will always be - # *empty* -- still a subset of [arg0, ..., arg(i-1)], but - # not a very interesting subset! - - def _match_long_opt( - self, opt: str, explicit_value: str | None, state: _ParsingState - ) -> None: - if opt not in self._long_opt: - raise NoSuchOption(opt, possibilities=self._long_opt, 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 = UNSET - - 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 = UNSET - - option.process(value, state) - - if stop: - break - - # If we got any unknown options we recombine the string of the - # remaining options and re-attach the prefix, then report that - # to the state as new large. 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 - ) -> str | cabc.Sequence[str] | T_UNSET | T_FLAG_NEEDS_VALUE: - nargs = option.nargs - - value: str | cabc.Sequence[str] | T_UNSET | T_FLAG_NEEDS_VALUE - - if len(state.rargs) < nargs: - if option.obj._flag_needs_value: - # Option allows omitting the value. - value = FLAG_NEEDS_VALUE - else: - raise BadOptionUsage( - option_name, - ngettext( - "Option {name!r} requires an argument.", - "Option {name!r} requires {nargs} arguments.", - nargs, - ).format(name=option_name, nargs=nargs), - ) - elif nargs == 1: - next_rarg = state.rargs[0] - - if ( - option.obj._flag_needs_value - and isinstance(next_rarg, str) - and next_rarg[:1] in self._opt_prefixes - and len(next_rarg) > 1 - ): - # The next arg looks like the start of an option, don't - # use it as the value if omitting the value is allowed. - value = FLAG_NEEDS_VALUE - else: - value = state.rargs.pop(0) - else: - value = tuple(state.rargs[:nargs]) - del state.rargs[:nargs] - - return value - - def _process_opts(self, arg: str, state: _ParsingState) -> None: - explicit_value = None - # Long option handling happens in two parts. The first part is - # supporting explicitly attached values. In any case, we will try - # to long match the option first. - if "=" in arg: - long_opt, explicit_value = arg.split("=", 1) - else: - long_opt = arg - norm_long_opt = _normalize_opt(long_opt, self.ctx) - - # At this point we will match the (assumed) long option through - # the long option matching code. Note that this allows options - # like "-foo" to be matched as long options. - try: - self._match_long_opt(norm_long_opt, explicit_value, state) - except NoSuchOption: - # At this point the long option matching failed, and we need - # to try with short options. However there is a special rule - # which says, that if we have a two character options prefix - # (applies to "--foo" for instance), we do not dispatch to the - # short option code and will instead raise the no option - # error. - if arg[:2] not in self._opt_prefixes: - self._match_short_opt(arg, state) - return - - if not self.ignore_unknown_options: - raise - - state.largs.append(arg) - - -def __getattr__(name: str) -> object: - import warnings - - if name in { - "OptionParser", - "Argument", - "Option", - "split_opt", - "normalize_opt", - "ParsingState", - }: - warnings.warn( - f"'parser.{name}' is deprecated and will be removed in Click 9.0." - " The old parser is available in 'optparse'.", - DeprecationWarning, - stacklevel=2, - ) - return globals()[f"_{name}"] - - if name == "split_arg_string": - from .shell_completion import split_arg_string - - warnings.warn( - "Importing 'parser.split_arg_string' is deprecated, it will only be" - " available in 'shell_completion' in Click 9.0.", - DeprecationWarning, - stacklevel=2, - ) - return split_arg_string - - raise AttributeError(name) diff --git a/server/venv/Lib/site-packages/click/py.typed b/server/venv/Lib/site-packages/click/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/server/venv/Lib/site-packages/click/shell_completion.py b/server/venv/Lib/site-packages/click/shell_completion.py deleted file mode 100644 index b01e290..0000000 --- a/server/venv/Lib/site-packages/click/shell_completion.py +++ /dev/null @@ -1,680 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import os -import re -import typing as t -from gettext import gettext as _ - -from .core import Argument -from .core import Command -from .core import Context -from .core import Group -from .core import Option -from .core import Parameter -from .core import ParameterSource -from .utils import echo - - -def shell_complete( - cli: Command, - ctx_args: cabc.MutableMapping[str, t.Any], - prog_name: str, - complete_var: str, - instruction: str, -) -> int: - """Perform shell completion for the given CLI program. - - :param cli: Command being called. - :param ctx_args: Extra arguments to pass to - ``cli.make_context``. - :param prog_name: Name of the executable in the shell. - :param complete_var: Name of the environment variable that holds - the completion instruction. - :param instruction: Value of ``complete_var`` with the completion - instruction and shell, in the form ``instruction_shell``. - :return: Status code to exit with. - """ - shell, _, instruction = instruction.partition("_") - comp_cls = get_completion_class(shell) - - if comp_cls is None: - return 1 - - comp = comp_cls(cli, ctx_args, prog_name, complete_var) - - # Write bytes, otherwise Windows text stdout translates LF to CRLF and breaks. - if instruction == "source": - echo(comp.source().encode(), nl=False) - return 0 - - if instruction == "complete": - echo(comp.complete().encode()) - return 0 - - return 1 - - -class CompletionItem: - """Represents a completion value and metadata about the value. The - default metadata is ``type`` to indicate special shell handling, - and ``help`` if a shell supports showing a help string next to the - value. - - Arbitrary parameters can be passed when creating the object, and - accessed using ``item.attr``. If an attribute wasn't passed, - accessing it returns ``None``. - - :param value: The completion suggestion. - :param type: Tells the shell script to provide special completion - support for the type. Click uses ``"dir"`` and ``"file"``. - :param help: String shown next to the value if supported. - :param kwargs: Arbitrary metadata. The built-in implementations - don't use this, but custom type completions paired with custom - shell support could use it. - """ - - __slots__ = ("value", "type", "help", "_info") - - def __init__( - self, - value: t.Any, - type: str = "plain", - help: str | None = None, - **kwargs: t.Any, - ) -> None: - self.value: t.Any = value - self.type: str = type - self.help: str | None = help - self._info = kwargs - - def __getattr__(self, name: str) -> t.Any: - return self._info.get(name) - - -# Only Bash >= 4.4 has the nosort option. -_SOURCE_BASH = """\ -%(complete_func)s() { - local IFS=$'\\n' - local response - - response=$(env COMP_WORDS="${COMP_WORDS[*]}" COMP_CWORD=$COMP_CWORD \ -%(complete_var)s=bash_complete $1) - - for completion in $response; do - IFS=',' read type value <<< "$completion" - - if [[ $type == 'dir' ]]; then - COMPREPLY=() - compopt -o dirnames - elif [[ $type == 'file' ]]; then - COMPREPLY=() - compopt -o default - elif [[ $type == 'plain' ]]; then - COMPREPLY+=($value) - fi - done - - return 0 -} - -%(complete_func)s_setup() { - complete -o nosort -F %(complete_func)s %(prog_name)s -} - -%(complete_func)s_setup; -""" - -# See ZshComplete.format_completion below, and issue #2703, before -# changing this script. -# -# (TL;DR: _describe is picky about the format, but this Zsh script snippet -# is already widely deployed. So freeze this script, and use clever-ish -# handling of colons in ZshComplet.format_completion.) -_SOURCE_ZSH = """\ -#compdef %(prog_name)s - -%(complete_func)s() { - local -a completions - local -a completions_with_descriptions - local -a response - (( ! $+commands[%(prog_name)s] )) && return 1 - - response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) \ -%(complete_var)s=zsh_complete %(prog_name)s)}") - - for type key descr in ${response}; do - if [[ "$type" == "plain" ]]; then - if [[ "$descr" == "_" ]]; then - completions+=("$key") - else - completions_with_descriptions+=("$key":"$descr") - fi - elif [[ "$type" == "dir" ]]; then - _path_files -/ - elif [[ "$type" == "file" ]]; then - _path_files -f - fi - done - - if [ -n "$completions_with_descriptions" ]; then - _describe -V unsorted completions_with_descriptions -U - fi - - if [ -n "$completions" ]; then - compadd -U -V unsorted -a completions - fi -} - -if [[ $zsh_eval_context[-1] == loadautofunc ]]; then - # autoload from fpath, call function directly - %(complete_func)s "$@" -else - # eval/source/. command, register function for later - compdef %(complete_func)s %(prog_name)s -fi -""" - -_SOURCE_FISH = """\ -function %(complete_func)s; - set -l response (env %(complete_var)s=fish_complete COMP_WORDS=(commandline -cp) \ -COMP_CWORD=(commandline -t) %(prog_name)s); - - for completion in $response; - set -l metadata (string split \n $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"; - if test $metadata[3] != "_"; - echo $metadata[2]\t$metadata[3]; - else; - echo $metadata[2]; - end; - end; - end; -end; - -complete --no-files --command %(prog_name)s --arguments \ -"(%(complete_func)s)"; -""" - - -class ShellComplete: - """Base class for providing shell completion support. A subclass for - a given shell will override attributes and methods to implement the - completion instructions (``source`` and ``complete``). - - :param cli: Command being called. - :param prog_name: Name of the executable in the shell. - :param complete_var: Name of the environment variable that holds - the completion instruction. - - .. versionadded:: 8.0 - """ - - name: t.ClassVar[str] - """Name to register the shell as with :func:`add_completion_class`. - This is used in completion instructions (``{name}_source`` and - ``{name}_complete``). - """ - - source_template: t.ClassVar[str] - """Completion script template formatted by :meth:`source`. This must - be provided by subclasses. - """ - - def __init__( - self, - cli: Command, - ctx_args: cabc.MutableMapping[str, t.Any], - prog_name: str, - complete_var: str, - ) -> None: - self.cli = cli - self.ctx_args = ctx_args - self.prog_name = prog_name - self.complete_var = complete_var - - @property - def func_name(self) -> str: - """The name of the shell function defined by the completion - script. - """ - safe_name = re.sub(r"\W*", "", self.prog_name.replace("-", "_"), flags=re.ASCII) - return f"_{safe_name}_completion" - - def source_vars(self) -> dict[str, t.Any]: - """Vars for formatting :attr:`source_template`. - - By default this provides ``complete_func``, ``complete_var``, - and ``prog_name``. - """ - return { - "complete_func": self.func_name, - "complete_var": self.complete_var, - "prog_name": self.prog_name, - } - - def source(self) -> str: - """Produce the shell script that defines the completion - function. By default this ``%``-style formats - :attr:`source_template` with the dict returned by - :meth:`source_vars`. - """ - return self.source_template % self.source_vars() - - def get_completion_args(self) -> tuple[list[str], str]: - """Use the env vars defined by the shell script to return a - tuple of ``args, incomplete``. This must be implemented by - subclasses. - """ - raise NotImplementedError - - def get_completions(self, args: list[str], incomplete: str) -> list[CompletionItem]: - """Determine the context and last complete command or parameter - from the complete args. Call that object's ``shell_complete`` - method to get the completions for the incomplete value. - - :param args: List of complete args before the incomplete value. - :param incomplete: Value being completed. May be empty. - """ - ctx = _resolve_context(self.cli, self.ctx_args, self.prog_name, args) - obj, incomplete = _resolve_incomplete(ctx, args, incomplete) - return obj.shell_complete(ctx, incomplete) - - def format_completion(self, item: CompletionItem) -> str: - """Format a completion item into the form recognized by the - shell script. This must be implemented by subclasses. - - :param item: Completion item to format. - """ - raise NotImplementedError - - def complete(self) -> str: - """Produce the completion data to send back to the shell. - - By default this calls :meth:`get_completion_args`, gets the - completions, then calls :meth:`format_completion` for each - completion. - """ - args, incomplete = self.get_completion_args() - completions = self.get_completions(args, incomplete) - out = [self.format_completion(item) for item in completions] - return "\n".join(out) - - -class BashComplete(ShellComplete): - """Shell completion for Bash.""" - - name = "bash" - source_template = _SOURCE_BASH - - @staticmethod - def _check_version() -> None: - import shutil - import subprocess - - bash_exe = shutil.which("bash") - - if bash_exe is None: - match = None - else: - output = subprocess.run( - [bash_exe, "--norc", "-c", 'echo "${BASH_VERSION}"'], - stdout=subprocess.PIPE, - ) - match = re.search(r"^(\d+)\.(\d+)\.\d+", output.stdout.decode()) - - if match is not None: - major, minor = match.groups() - - if major < "4" or major == "4" and minor < "4": - echo( - _( - "Shell completion is not supported for Bash" - " versions older than 4.4." - ), - err=True, - ) - else: - echo( - _("Couldn't detect Bash version, shell completion is not supported."), - err=True, - ) - - def source(self) -> str: - self._check_version() - return super().source() - - def get_completion_args(self) -> tuple[list[str], str]: - cwords = split_arg_string(os.environ["COMP_WORDS"]) - cword = int(os.environ["COMP_CWORD"]) - args = cwords[1:cword] - - try: - incomplete = cwords[cword] - except IndexError: - incomplete = "" - - return args, incomplete - - def format_completion(self, item: CompletionItem) -> str: - return f"{item.type},{item.value}" - - -class ZshComplete(ShellComplete): - """Shell completion for Zsh.""" - - name = "zsh" - source_template = _SOURCE_ZSH - - def get_completion_args(self) -> tuple[list[str], str]: - cwords = split_arg_string(os.environ["COMP_WORDS"]) - cword = int(os.environ["COMP_CWORD"]) - args = cwords[1:cword] - - try: - incomplete = cwords[cword] - except IndexError: - incomplete = "" - - return args, incomplete - - def format_completion(self, item: CompletionItem) -> str: - help_ = item.help or "_" - # The zsh completion script uses `_describe` on items with help - # texts (which splits the item help from the item value at the - # first unescaped colon) and `compadd` on items without help - # text (which uses the item value as-is and does not support - # colon escaping). So escape colons in the item value if and - # only if the item help is not the sentinel "_" value, as used - # by the completion script. - # - # (The zsh completion script is potentially widely deployed, and - # thus harder to fix than this method.) - # - # See issue #1812 and issue #2703 for further context. - value = item.value.replace(":", r"\:") if help_ != "_" else item.value - return f"{item.type}\n{value}\n{help_}" - - -class FishComplete(ShellComplete): - """Shell completion for Fish.""" - - name = "fish" - source_template = _SOURCE_FISH - - def get_completion_args(self) -> tuple[list[str], str]: - cwords = split_arg_string(os.environ["COMP_WORDS"]) - incomplete = os.environ["COMP_CWORD"] - if incomplete: - incomplete = split_arg_string(incomplete)[0] - 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: - """ - .. versionchanged:: 8.4.0 - Escape newlines in value and help to fix completion errors with - multi-line help strings. - """ - # The fish completion script splits each response line on literal - # newlines, so any newline in the value or help would corrupt the - # frame. Replace them with the two-character escape "\n" so the text - # round-trips through fish without breaking the format. The "_" - # sentinel for missing help mirrors :class:`ZshComplete`. - help_ = item.help or "_" - value = item.value.replace("\n", r"\n") - help_escaped = help_.replace("\n", r"\n") - return f"{item.type}\n{value}\n{help_escaped}" - - -ShellCompleteType = t.TypeVar("ShellCompleteType", bound="type[ShellComplete]") - - -_available_shells: dict[str, type[ShellComplete]] = { - "bash": BashComplete, - "fish": FishComplete, - "zsh": ZshComplete, -} - - -def add_completion_class( - cls: ShellCompleteType, name: str | None = None -) -> ShellCompleteType: - """Register a :class:`ShellComplete` subclass under the given name. - The name will be provided by the completion instruction environment - variable during completion. - - :param cls: The completion class that will handle completion for the - shell. - :param name: Name to register the class under. Defaults to the - class's ``name`` attribute. - """ - if name is None: - name = cls.name - - _available_shells[name] = cls - - return cls - - -def get_completion_class(shell: str) -> type[ShellComplete] | None: - """Look up a registered :class:`ShellComplete` subclass by the name - provided by the completion instruction environment variable. If the - name isn't registered, returns ``None``. - - :param shell: Name the class is registered under. - """ - return _available_shells.get(shell) - - -def split_arg_string(string: str) -> list[str]: - """Split an argument string as with :func:`shlex.split`, but don't - fail if the string is incomplete. Ignores a missing closing quote or - incomplete escape sequence and uses the partial token as-is. - - .. code-block:: python - - split_arg_string("example 'my file") - ["example", "my file"] - - split_arg_string("example my\\") - ["example", "my"] - - :param string: String to split. - - .. versionchanged:: 8.2 - Moved to ``shell_completion`` from ``parser``. - """ - import shlex - - lex = shlex.shlex(string, posix=True) - lex.whitespace_split = True - lex.commenters = "" - out = [] - - try: - for token in lex: - out.append(token) - except ValueError: - # Raised when end-of-string is reached in an invalid state. Use - # the partial token as-is. The quote or escape character is in - # lex.state, not lex.token. - out.append(lex.token) - - return out - - -def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool: - """Determine if the given parameter is an argument that can still - accept values. - - :param ctx: Invocation context for the command represented by the - parsed complete args. - :param param: Argument object being checked. - """ - if not isinstance(param, Argument): - return False - - value = ctx.params.get(param.name) - return ( - param.nargs == -1 - or ctx.get_parameter_source(param.name) is not ParameterSource.COMMANDLINE - or ( - param.nargs > 1 - and isinstance(value, (tuple, list)) - and len(value) < param.nargs - ) - ) - - -def _start_of_option(ctx: Context, value: str) -> bool: - """Check if the value looks like the start of an option.""" - if not value: - return False - - c = value[0] - return c in ctx._opt_prefixes - - -def _is_incomplete_option(ctx: Context, args: list[str], param: Parameter) -> bool: - """Determine if the given parameter is an option that needs a value. - - :param args: List of complete args before the incomplete value. - :param param: Option object being checked. - """ - if not isinstance(param, Option): - return False - - if param.is_flag or param.count: - return False - - last_option = None - - for index, arg in enumerate(reversed(args)): - if index + 1 > param.nargs: - break - - if _start_of_option(ctx, arg): - last_option = arg - break - - return last_option is not None and last_option in param.opts - - -def _resolve_context( - cli: Command, - ctx_args: cabc.MutableMapping[str, t.Any], - prog_name: str, - args: list[str], -) -> Context: - """Produce the context hierarchy starting with the command and - traversing the complete arguments. This only follows the commands, - it doesn't trigger input prompts or callbacks. - - :param cli: Command being called. - :param prog_name: Name of the executable in the shell. - :param args: List of complete args before the incomplete value. - """ - ctx_args["resilient_parsing"] = True - with cli.make_context(prog_name, args.copy(), **ctx_args) as ctx: - args = ctx._protected_args + ctx.args - - while args: - command = ctx.command - - if isinstance(command, Group): - if not command.chain: - name, cmd, args = command.resolve_command(ctx, args) - - if cmd is None: - return ctx - - with cmd.make_context( - name, args, parent=ctx, resilient_parsing=True - ) as sub_ctx: - ctx = sub_ctx - args = ctx._protected_args + ctx.args - else: - sub_ctx = ctx - - while args: - name, cmd, args = command.resolve_command(ctx, args) - - if cmd is None: - return ctx - - with cmd.make_context( - name, - args, - parent=ctx, - allow_extra_args=True, - allow_interspersed_args=False, - resilient_parsing=True, - ) as sub_sub_ctx: - sub_ctx = sub_sub_ctx - args = sub_ctx.args - - ctx = sub_ctx - args = [*sub_ctx._protected_args, *sub_ctx.args] - else: - break - - return ctx - - -def _resolve_incomplete( - ctx: Context, args: list[str], incomplete: str -) -> tuple[Command | Parameter, str]: - """Find the Click object that will handle the completion of the - incomplete value. Return the object and the incomplete value. - - :param ctx: Invocation context for the command represented by - the parsed complete args. - :param args: List of complete args before the incomplete value. - :param incomplete: Value being completed. May be empty. - """ - # Different shells treat an "=" between a long option name and - # value differently. Might keep the value joined, return the "=" - # as a separate item, or return the split name and value. Always - # split and discard the "=" to make completion easier. - if incomplete == "=": - incomplete = "" - elif "=" in incomplete and _start_of_option(ctx, incomplete): - name, _, incomplete = incomplete.partition("=") - args.append(name) - - # The "--" marker tells Click to stop treating values as options - # even if they start with the option character. If it hasn't been - # given and the incomplete arg looks like an option, the current - # command will provide option name completions. - if "--" not in args and _start_of_option(ctx, incomplete): - return ctx.command, incomplete - - params = ctx.command.get_params(ctx) - - # If the last complete arg is an option name with an incomplete - # value, the option will provide value completions. - for param in params: - if _is_incomplete_option(ctx, args, param): - return param, incomplete - - # It's not an option name or value. The first argument without a - # parsed value will provide value completions. - for param in params: - if _is_incomplete_argument(ctx, param): - return param, incomplete - - # There were no unparsed arguments, the command may be a group that - # will provide command name completions. - return ctx.command, incomplete diff --git a/server/venv/Lib/site-packages/click/termui.py b/server/venv/Lib/site-packages/click/termui.py deleted file mode 100644 index 91ef6e1..0000000 --- a/server/venv/Lib/site-packages/click/termui.py +++ /dev/null @@ -1,941 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import inspect -import io -import itertools -import re -import sys -import typing as t -from contextlib import AbstractContextManager -from contextlib import redirect_stdout -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" - - -_HIDDEN_INPUT_MASK = "'***'" - - -def _mask_hidden_input(message: str, value: str) -> str: - """Replace occurrences of ``value`` in ``message`` with a fixed mask. - - Both ``repr(value)`` (the form built-in :class:`ParamType` errors use - via ``{value!r}``) and the raw value are masked. The raw-value pass - uses word-boundary lookarounds so a substring like ``"1"`` does not - match inside ``"10"``, and ``"ent"`` does not match inside - ``"Authentication"``. The empty string is skipped to avoid matching - at every boundary. - """ - message = message.replace(repr(value), _HIDDEN_INPUT_MASK) - if value: - message = re.sub( - rf"(? str: - import getpass - - return getpass.getpass(prompt) - - -def _readline_prompt(func: t.Callable[[str], str], text: str, err: bool) -> str: - """Call a prompt function, passing the full prompt on non-Windows so - readline can handle line editing and cursor positioning correctly. - - On Windows the prompt is written separately via :func:`echo` for - colorama support, with only the last character passed to *func*. - """ - if WIN: - # Write the prompt separately so that we get nice coloring - # through colorama on Windows. - echo(text[:-1], nl=False, err=err) - # Echo the last character to stdout to work around an issue - # where readline causes backspace to clear the whole line. - return func(text[-1:]) - if err: - with redirect_stdout(sys.stderr): - return func(text) - return func(text) - - -def _build_prompt( - text: str, - suffix: str, - show_default: bool | str = False, - default: t.Any | None = None, - show_choices: bool = True, - type: ParamType[t.Any] | None = None, -) -> str: - prompt = text - if type is not None and show_choices and isinstance(type, Choice): - prompt += f" ({', '.join(map(str, type.choices))})" - if isinstance(show_default, str): - default = f"({show_default})" - if default is not None and show_default: - prompt = f"{prompt} [{_format_default(default)}]" - return f"{prompt}{suffix}" - - -def _format_default(default: t.Any) -> t.Any: - if isinstance(default, (io.IOBase, LazyFile)) and hasattr(default, "name"): - return default.name - - return default - - -def prompt( - text: str, - default: t.Any | None = None, - hide_input: bool = False, - confirmation_prompt: bool | str = False, - type: ParamType[t.Any] | t.Any | None = None, - value_proc: t.Callable[[str], t.Any] | None = None, - prompt_suffix: str = ": ", - show_default: bool | str = 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. - If this value is a string, it shows that string - in parentheses instead of the actual value. - :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): ". - - .. versionchanged:: 8.3.3 - ``show_default`` can be a string to show a custom value instead - of the actual default, matching the help text behavior. - - .. versionchanged:: 8.3.1 - A space is no longer appended to the prompt. - - .. 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: - return _readline_prompt(f, text, err) - 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: - message = _mask_hidden_input(e.message, value) if hide_input else e.message - echo(_("Error: {message}").format(message=message), err=err) - continue - if not confirmation_prompt: - return result - while True: - value2 = prompt_func(confirmation_prompt) - is_empty = not value and not value2 - if value2 or is_empty: - break - if value == value2: - return result - echo(_("Error: The two entered values do not match."), err=err) - - -def confirm( - text: str, - default: bool | None = False, - abort: bool = False, - prompt_suffix: str = ": ", - show_default: bool = True, - err: bool = False, -) -> bool: - """Prompts for confirmation (yes/no question). - - If the user aborts the input by sending a interrupt signal this - function will catch it and raise a :exc:`Abort` exception. - - :param text: the question to ask. - :param default: The default value to use when no input is given. If - ``None``, repeat until input is given. - :param abort: if this is set to `True` a negative answer aborts the - exception by raising :exc:`Abort`. - :param prompt_suffix: a suffix that should be added to the prompt. - :param show_default: shows or hides the default value in the prompt. - :param err: if set to true the file defaults to ``stderr`` instead of - ``stdout``, the same as with echo. - - .. versionchanged:: 8.3.1 - A space is no longer appended to the prompt. - - .. 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: - value = _readline_prompt(visible_prompt_func, prompt, err).lower().strip() - except (KeyboardInterrupt, EOFError): - raise Abort() from None - if value in ("y", "yes"): - rv = True - elif value in ("n", "no"): - rv = False - elif default is not None and value == "": - rv = default - else: - echo(_("Error: invalid input"), err=err) - continue - break - if abort and not rv: - raise Abort() - return rv - - -def get_pager_file( - color: bool | None = None, -) -> t.ContextManager[t.TextIO]: - """Context manager. - - Yields a writable file-like object which can be used as an output pager. - - .. versionadded:: 8.4.0 - - :param color: controls if the pager supports ANSI colors or not. The - default is autodetection. - """ - from ._termui_impl import get_pager_file - - color = resolve_color_default(color) - - return get_pager_file(color=color) - - -def echo_via_pager( - text_or_generator: cabc.Iterable[str] | t.Callable[[], cabc.Iterable[str]] | str, - color: bool | None = None, -) -> None: - """This function takes a text and shows it via an environment specific - pager on stdout. - - .. versionchanged:: 3.0 - Added the `color` flag. - - :param text_or_generator: the text to page, or alternatively, a - generator emitting the text to page. - :param color: controls if the pager supports ANSI colors or not. The - default is autodetection. - """ - - if inspect.isgeneratorfunction(text_or_generator): - i = t.cast("t.Callable[[], cabc.Iterable[str]]", text_or_generator)() - elif isinstance(text_or_generator, str): - i = [text_or_generator] - else: - i = iter(t.cast("cabc.Iterable[str]", text_or_generator)) - - # convert every element of i to a text type if necessary - text_generator = (el if isinstance(el, str) else str(el) for el in i) - - with get_pager_file(color=color) as pager: - for text in itertools.chain(text_generator, "\n"): - pager.write(text) - - -@t.overload -def progressbar( - *, - length: int, - label: str | None = None, - hidden: bool = False, - show_eta: bool = True, - show_percent: bool | None = None, - show_pos: bool = False, - fill_char: str = "#", - empty_char: str = "-", - bar_template: str = "%(label)s [%(bar)s] %(info)s", - info_sep: str = " ", - width: int = 36, - file: t.TextIO | None = None, - color: bool | None = None, - update_min_steps: int = 1, -) -> ProgressBar[int]: ... - - -@t.overload -def progressbar( - iterable: cabc.Iterable[V] | None = None, - length: int | None = None, - label: str | None = None, - hidden: bool = False, - show_eta: bool = True, - show_percent: bool | None = None, - show_pos: bool = False, - item_show_func: t.Callable[[V | None], str | None] | None = None, - fill_char: str = "#", - empty_char: str = "-", - bar_template: str = "%(label)s [%(bar)s] %(info)s", - info_sep: str = " ", - width: int = 36, - file: t.TextIO | None = None, - color: bool | None = None, - update_min_steps: int = 1, -) -> ProgressBar[V]: ... - - -def progressbar( - iterable: cabc.Iterable[V] | None = None, - length: int | None = None, - label: str | None = None, - hidden: bool = False, - show_eta: bool = True, - show_percent: bool | None = None, - show_pos: bool = False, - item_show_func: t.Callable[[V | None], str | None] | None = None, - fill_char: str = "#", - empty_char: str = "-", - bar_template: str = "%(label)s [%(bar)s] %(info)s", - info_sep: str = " ", - width: int = 36, - file: t.TextIO | None = None, - color: bool | None = None, - update_min_steps: int = 1, -) -> ProgressBar[V]: - """This function creates an iterable context manager that can be used - to iterate over something while showing a progress bar. It will - either iterate over the `iterable` or `length` items (that are counted - up). While iteration happens, this function will print a rendered - progress bar to the given `file` (defaults to stdout) and will attempt - to calculate remaining time and more. By default, this progress bar - will not be rendered if the file is not a terminal. - - The context manager creates the progress bar. When the context - manager is entered the progress bar is already created. With every - iteration over the progress bar, the iterable passed to the bar is - advanced and the bar is updated. When the context manager exits, - a newline is printed and the progress bar is finalized on screen. - - Note: The progress bar is currently designed for use cases where the - total progress can be expected to take at least several seconds. - Because of this, the ProgressBar class object won't display - progress that is considered too fast, and progress where the time - between steps is less than a second. - - No printing must happen or the progress bar will be unintentionally - destroyed. - - Example usage:: - - with progressbar(items) as bar: - for item in bar: - do_something_with(item) - - Alternatively, if no iterable is specified, one can manually update the - progress bar through the `update()` method instead of directly - iterating over the progress bar. The update method accepts the number - of steps to increment the bar with:: - - with progressbar(length=chunks.total_bytes) as bar: - for chunk in chunks: - process_chunk(chunk) - bar.update(chunks.bytes) - - The ``update()`` method also takes an optional value specifying the - ``current_item`` at the new position. This is useful when used - together with ``item_show_func`` to customize the output for each - manual step:: - - with click.progressbar( - length=total_size, - label='Unzipping archive', - item_show_func=lambda a: a.filename - ) as bar: - for archive in zip_file: - archive.extract() - bar.update(archive.size, archive) - - :param iterable: an iterable to iterate over. If not provided the length - is required. - :param length: the number of items to iterate over. By default the - progressbar will attempt to ask the iterator about its - length, which might or might not work. If an iterable is - also provided this parameter can be used to override the - length. If an iterable is not provided the progress bar - will iterate over a range of that length. - :param label: the label to show next to the progress bar. - :param hidden: hide the progressbar. Defaults to ``False``. When no tty is - detected, it will only print the progressbar label. Setting this to - ``False`` also disables that. - :param show_eta: enables or disables the estimated time display. This is - automatically disabled if the length cannot be - determined. - :param show_percent: enables or disables the percentage display. The - default is `True` if the iterable has a length or - `False` if not. - :param show_pos: enables or disables the absolute position display. The - default is `False`. - :param item_show_func: A function called with the current item which - can return a string to show next to the progress bar. If the - function returns ``None`` nothing is shown. The current item can - be ``None``, such as when entering and exiting the bar. - :param fill_char: the character to use to show the filled part of the - progress bar. - :param empty_char: the character to use to show the non-filled part of - the progress bar. - :param bar_template: the format string to use as template for the bar. - The parameters in it are ``label`` for the label, - ``bar`` for the progress bar and ``info`` for the - info section. - :param info_sep: the separator between multiple info items (eta etc.) - :param width: the width of the progress bar in characters, 0 means full - terminal width - :param file: The file to write to. If this is not a terminal then - only the label is printed. - :param color: controls if the terminal supports ANSI colors or not. The - default is autodetection. This is only needed if ANSI - codes are included anywhere in the progress bar output - which is not the case by default. - :param update_min_steps: Render only when this many updates have - completed. This allows tuning for very fast iterators. - - .. versionadded:: 8.2 - The ``hidden`` argument. - - .. versionchanged:: 8.0 - Output is shown even if execution time is less than 0.5 seconds. - - .. versionchanged:: 8.0 - ``item_show_func`` shows the current item, not the previous one. - - .. versionchanged:: 8.0 - Labels are echoed if the output is not a TTY. Reverts a change - in 7.0 that removed all output. - - .. versionadded:: 8.0 - The ``update_min_steps`` parameter. - - .. versionadded:: 4.0 - The ``color`` parameter and ``update`` method. - - .. versionadded:: 2.0 - """ - from ._termui_impl import ProgressBar - - color = resolve_color_default(color) - return ProgressBar( - iterable=iterable, - length=length, - hidden=hidden, - show_eta=show_eta, - show_percent=show_percent, - show_pos=show_pos, - item_show_func=item_show_func, - fill_char=fill_char, - empty_char=empty_char, - bar_template=bar_template, - info_sep=info_sep, - file=file, - label=label, - width=width, - color=color, - update_min_steps=update_min_steps, - ) - - -def clear() -> None: - """Clears the terminal screen. This will have the effect of clearing - the whole visible space of the terminal and moving the cursor to the - top left. This does not do anything if not connected to a terminal. - - .. versionadded:: 2.0 - """ - if not isatty(sys.stdout): - return - - # ANSI escape \033[2J clears the screen, \033[1;1H moves the cursor - echo("\033[2J\033[1;1H", nl=False) - - -def _interpret_color(color: int | tuple[int, int, int] | str, offset: int = 0) -> str: - if isinstance(color, int): - return f"{38 + offset};5;{color:d}" - - if isinstance(color, (tuple, list)): - r, g, b = color - return f"{38 + offset};2;{r:d};{g:d};{b:d}" - - return str(_ansi_colors[color] + offset) - - -def style( - text: t.Any, - fg: int | tuple[int, int, int] | str | None = None, - bg: int | tuple[int, int, int] | str | None = None, - bold: bool | None = None, - dim: bool | None = None, - underline: bool | None = None, - overline: bool | None = None, - italic: bool | None = None, - blink: bool | None = None, - reverse: bool | None = None, - strikethrough: bool | None = None, - reset: bool = True, -) -> str: - """Styles a text with ANSI styles and returns the new string. By - default the styling is self contained which means that at the end - of the string a reset code is issued. This can be prevented by - passing ``reset=False``. - - Examples:: - - click.echo(click.style('Hello World!', fg='green')) - click.echo(click.style('ATTENTION!', blink=True)) - click.echo(click.style('Some things', reverse=True, fg='cyan')) - click.echo(click.style('More colors', fg=(255, 12, 128), bg=117)) - - Supported color names: - - * ``black`` (might be a gray) - * ``red`` - * ``green`` - * ``yellow`` (might be an orange) - * ``blue`` - * ``magenta`` - * ``cyan`` - * ``white`` (might be light gray) - * ``bright_black`` - * ``bright_red`` - * ``bright_green`` - * ``bright_yellow`` - * ``bright_blue`` - * ``bright_magenta`` - * ``bright_cyan`` - * ``bright_white`` - * ``reset`` (reset the color code only) - - If the terminal supports it, color may also be specified as: - - - An integer in the interval [0, 255]. The terminal must support - 8-bit/256-color mode. - - An RGB tuple of three integers in [0, 255]. The terminal must - support 24-bit/true-color mode. - - See https://en.wikipedia.org/wiki/ANSI_color and - https://gist.github.com/XVilka/8346728 for more information. - - :param text: the string to style with ansi codes. - :param fg: if provided this will become the foreground color. - :param bg: if provided this will become the background color. - :param bold: if provided this will enable or disable bold mode. - :param dim: if provided this will enable or disable dim mode. This is - badly supported. - :param underline: if provided this will enable or disable underline. - :param overline: if provided this will enable or disable overline. - :param italic: if provided this will enable or disable italic. - :param blink: if provided this will enable or disable blinking. - :param reverse: if provided this will enable or disable inverse - rendering (foreground becomes background and the - other way round). - :param strikethrough: if provided this will enable or disable - striking through text. - :param reset: by default a reset-all code is added at the end of the - string which means that styles do not carry over. This - can be disabled to compose styles. - - .. versionchanged:: 8.0 - A non-string ``message`` is converted to a string. - - .. versionchanged:: 8.0 - Added support for 256 and RGB color codes. - - .. versionchanged:: 8.0 - Added the ``strikethrough``, ``italic``, and ``overline`` - parameters. - - .. versionchanged:: 7.0 - Added support for bright colors. - - .. versionadded:: 2.0 - """ - if not isinstance(text, str): - text = str(text) - - bits = [] - - if fg: - try: - bits.append(f"\033[{_interpret_color(fg)}m") - except KeyError: - raise TypeError(_("Unknown color {colour!r}").format(colour=fg)) from None - - if bg: - try: - bits.append(f"\033[{_interpret_color(bg, 10)}m") - except KeyError: - raise TypeError(_("Unknown color {colour!r}").format(colour=bg)) from None - - if bold is not None: - bits.append(f"\033[{1 if bold else 22}m") - if dim is not None: - bits.append(f"\033[{2 if dim else 22}m") - if underline is not None: - bits.append(f"\033[{4 if underline else 24}m") - if overline is not None: - bits.append(f"\033[{53 if overline else 55}m") - if italic is not None: - bits.append(f"\033[{3 if italic else 23}m") - if blink is not None: - bits.append(f"\033[{5 if blink else 25}m") - if reverse is not None: - bits.append(f"\033[{7 if reverse else 27}m") - if strikethrough is not None: - bits.append(f"\033[{9 if strikethrough else 29}m") - bits.append(text) - if reset: - bits.append(_ansi_reset_all) - return "".join(bits) - - -def unstyle(text: str) -> str: - """Removes ANSI styling information from a string. Usually it's not - necessary to use this function as Click's echo function will - automatically remove styling if necessary. - - .. versionadded:: 2.0 - - :param text: the text to remove style information from. - """ - return strip_ansi(text) - - -def secho( - message: t.Any | None = None, - file: t.IO[t.AnyStr] | None = None, - nl: bool = True, - err: bool = False, - color: bool | None = None, - **styles: t.Any, -) -> None: - """This function combines :func:`echo` and :func:`style` into one - call. As such the following two calls are the same:: - - click.secho('Hello World!', fg='green') - click.echo(click.style('Hello World!', fg='green')) - - All keyword arguments are forwarded to the underlying functions - depending on which one they go with. - - Non-string types will be converted to :class:`str`. However, - :class:`bytes` are passed directly to :meth:`echo` without applying - style. If you want to style bytes that represent text, call - :meth:`bytes.decode` first. - - .. versionchanged:: 8.0 - A non-string ``message`` is converted to a string. Bytes are - passed through without style applied. - - .. versionadded:: 2.0 - """ - if message is not None and not isinstance(message, (bytes, bytearray)): - message = style(message, **styles) - - return echo(message, file=file, nl=nl, err=err, color=color) - - -@t.overload -def edit( - text: bytes | bytearray, - editor: str | None = None, - env: cabc.Mapping[str, str] | None = None, - require_save: bool = False, - extension: str = ".txt", -) -> bytes | None: ... - - -@t.overload -def edit( - text: str, - editor: str | None = None, - env: cabc.Mapping[str, str] | None = None, - require_save: bool = True, - extension: str = ".txt", -) -> str | None: ... - - -@t.overload -def edit( - text: None = None, - editor: str | None = None, - env: cabc.Mapping[str, str] | None = None, - require_save: bool = True, - extension: str = ".txt", - filename: str | cabc.Iterable[str] | None = None, -) -> None: ... - - -def edit( - text: str | bytes | bytearray | None = None, - editor: str | None = None, - env: cabc.Mapping[str, str] | None = None, - require_save: bool = True, - extension: str = ".txt", - filename: str | cabc.Iterable[str] | None = None, -) -> str | bytes | bytearray | None: - r"""Edits the given text in the defined editor. If an editor is given - (should be the full path to the executable but the regular operating - system search path is used for finding the executable) it overrides - the detected editor. Optionally, some environment variables can be - used. If the editor is closed without changes, `None` is returned. In - case a file is edited directly the return value is always `None` and - `require_save` and `extension` are ignored. - - If the editor cannot be opened a :exc:`UsageError` is raised. - - Note for Windows: to simplify cross-platform usage, the newlines are - automatically converted from POSIX to Windows and vice versa. As such, - the message here will have ``\n`` as newline markers. - - :param text: the text to edit. - :param editor: optionally the editor to use. Defaults to automatic - detection. - :param env: environment variables to forward to the editor. - :param require_save: if this is true, then not saving in the editor - will make the return value become `None`. - :param extension: the extension to tell the editor about. This defaults - to `.txt` but changing this might change syntax - highlighting. - :param filename: if provided it will edit this file instead of the - provided text contents. It will not use a temporary - file as an indirection in that case. If the editor supports - editing multiple files at once, a sequence of files may be - passed as well. Invoke `click.file` once per file instead - if multiple files cannot be managed at once or editing the - files serially is desired. - - .. versionchanged:: 8.2.0 - ``filename`` now accepts any ``Iterable[str]`` in addition to a ``str`` - if the ``editor`` supports editing multiple files at once. - - """ - from ._termui_impl import Editor - - ed = Editor(editor=editor, env=env, require_save=require_save, extension=extension) - - if filename is None: - return ed.edit(text) - - if isinstance(filename, str): - filename = (filename,) - - ed.edit_files(filenames=filename) - return None - - -def launch(url: str, wait: bool = False, locate: bool = False) -> int: - """This function launches the given URL (or filename) in the default - viewer application for this file type. If this is an executable, it - might launch the executable in a new session. The return value is - the exit code of the launched application. Usually, ``0`` indicates - success. - - Examples:: - - click.launch('https://click.palletsprojects.com/') - click.launch('/my/downloaded/file', locate=True) - - .. versionadded:: 2.0 - - :param url: URL or filename of the thing to launch. - :param wait: Wait for the program to exit before returning. This - only works if the launched program blocks. In particular, - ``xdg-open`` on Linux does not block. - :param locate: if this is set to `True` then instead of launching the - application associated with the URL it will attempt to - launch a file manager with the file located. This - might have weird effects if the URL does not point to - the filesystem. - """ - from ._termui_impl import open_url - - return open_url(url, wait=wait, locate=locate) - - -# If this is provided, getchar() calls into this instead. This is used -# for unittesting purposes. -_getchar: t.Callable[[bool], str] | None = None - - -def getchar(echo: bool = False) -> str: - """Fetches a single character from the terminal and returns it. This - will always return a unicode character and under certain rare - circumstances this might return more than one character. The - situations which more than one character is returned is when for - whatever reason multiple characters end up in the terminal buffer or - standard input was not actually a terminal. - - Note that this will always read from the terminal, even if something - is piped into the standard input. - - Note for Windows: in rare cases when typing non-ASCII characters, this - function might wait for a second character and then return both at once. - This is because certain Unicode characters look like special-key markers. - - .. versionadded:: 2.0 - - :param echo: if set to `True`, the character read will also show up on - the terminal. The default is to not show it. - """ - global _getchar - - if _getchar is None: - from ._termui_impl import getchar as f - - _getchar = f - - return _getchar(echo) - - -def raw_terminal() -> AbstractContextManager[int]: - from ._termui_impl import raw_terminal as f - - return f() - - -def pause(info: str | None = None, err: bool = False) -> None: - """This command stops execution and waits for the user to press any - key to continue. This is similar to the Windows batch "pause" - command. If the program is not run through a terminal, this command - will instead do nothing. - - .. versionadded:: 2.0 - - .. versionadded:: 4.0 - Added the `err` parameter. - - :param info: The message to print before pausing. Defaults to - ``"Press any key to continue..."``. - :param err: if set to message goes to ``stderr`` instead of - ``stdout``, the same as with echo. - """ - if not isatty(sys.stdin) or not isatty(sys.stdout): - return - - if info is None: - info = _("Press any key to continue...") - - try: - if info: - echo(info, nl=False, err=err) - try: - getchar() - except (KeyboardInterrupt, EOFError): - pass - finally: - if info: - echo(err=err) diff --git a/server/venv/Lib/site-packages/click/testing.py b/server/venv/Lib/site-packages/click/testing.py deleted file mode 100644 index 1eb81d2..0000000 --- a/server/venv/Lib/site-packages/click/testing.py +++ /dev/null @@ -1,736 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import contextlib -import io -import os -import pdb -import shlex -import sys -import tempfile -import typing as t -from types import TracebackType - -from . import _compat -from . import formatting -from . import termui -from . import utils -from ._compat import _find_binary_reader - -if t.TYPE_CHECKING: - from _typeshed import ReadableBuffer - - from .core import Command - -CaptureMode = t.Literal["sys", "fd"] - - -class EchoingStdin: - def __init__(self, input: t.BinaryIO, output: t.BinaryIO) -> None: - self._input = input - self._output = output - self._paused = False - - def __getattr__(self, x: str) -> t.Any: - return getattr(self._input, x) - - def _echo(self, rv: bytes) -> bytes: - if not self._paused: - self._output.write(rv) - - return rv - - def read(self, n: int = -1) -> bytes: - return self._echo(self._input.read(n)) - - def read1(self, n: int = -1) -> bytes: - return self._echo(self._input.read1(n)) # type: ignore - - def readline(self, n: int = -1) -> bytes: - return self._echo(self._input.readline(n)) - - def readlines(self) -> list[bytes]: - return [self._echo(x) for x in self._input.readlines()] - - def __iter__(self) -> cabc.Iterator[bytes]: - return iter(self._echo(x) for x in self._input) - - def __repr__(self) -> str: - return repr(self._input) - - -@contextlib.contextmanager -def _pause_echo(stream: EchoingStdin | None) -> cabc.Iterator[None]: - if stream is None: - yield - else: - stream._paused = True - yield - stream._paused = False - - -class _FDCapture: - """Redirect a file descriptor to a temporary file for capture. - - Saves the current target of *targetfd* via :func:`os.dup`, then - redirects it to a temporary file via :func:`os.dup2`. On - :meth:`stop`, restores the original ``fd`` and returns the captured - bytes. Inspired by Pytest's ``FDCapture``. - - .. versionadded:: 8.4.0 - """ - - def __init__(self, targetfd: int) -> None: - self._targetfd = targetfd - self.saved_fd: int = -1 - self._tmpfile: t.BinaryIO | None = None - - def start(self) -> None: - self.saved_fd = os.dup(self._targetfd) - self._tmpfile = tempfile.TemporaryFile(buffering=0) - os.dup2(self._tmpfile.fileno(), self._targetfd) - - def stop(self) -> bytes: - assert self._tmpfile is not None, "_FDCapture.start() was not called" - os.dup2(self.saved_fd, self._targetfd) - os.close(self.saved_fd) - self.saved_fd = -1 - self._tmpfile.seek(0) - data = self._tmpfile.read() - self._tmpfile.close() - self._tmpfile = None - return data - - -class BytesIOCopy(io.BytesIO): - """Patch ``io.BytesIO`` to let the written stream be copied to another. - - .. versionadded:: 8.2 - """ - - def __init__(self, copy_to: io.BytesIO) -> None: - super().__init__() - self.copy_to = copy_to - - def flush(self) -> None: - super().flush() - self.copy_to.flush() - - def write(self, b: ReadableBuffer) -> int: - self.copy_to.write(b) - return super().write(b) - - -class StreamMixer: - """Mixes `` and `` streams. - - The result is available in the ``output`` attribute. - - .. versionadded:: 8.2 - """ - - def __init__(self) -> None: - self.output: io.BytesIO = io.BytesIO() - self.stdout: io.BytesIO = BytesIOCopy(copy_to=self.output) - self.stderr: io.BytesIO = BytesIOCopy(copy_to=self.output) - - -class _NamedTextIOWrapper(io.TextIOWrapper): - """A :class:`~io.TextIOWrapper` with custom ``name`` and ``mode`` - that does not close its underlying buffer. - - When ``CliRunner`` runs in ``fd`` mode, ``_original_fd`` is patched to - point at the saved (pre-redirection) ``fd``, so C-level consumers that call - :meth:`fileno` (like ``faulthandler`` or ``subprocess``) keep working. In - the default ``sys`` mode ``_original_fd`` stays at ``-1`` and - :meth:`fileno` raises :exc:`io.UnsupportedOperation`, matching the - pre-``8.3.3`` behavior. - """ - - def __init__( - self, - buffer: t.BinaryIO, - name: str, - mode: str, - **kwargs: t.Any, - ) -> None: - super().__init__(buffer, **kwargs) - self._name = name - self._mode = mode - self._original_fd: int = -1 - - def close(self) -> None: - """The buffer this object contains belongs to some other object, - so prevent the default ``__del__`` implementation from closing - that buffer. - - .. versionadded:: 8.3.2 - """ - - def fileno(self) -> int: - """Return the file descriptor of the saved original stream when - ``CliRunner`` runs in ``fd`` mode. Otherwise delegate to - :class:`~io.TextIOWrapper`, which raises - :exc:`io.UnsupportedOperation` for a ``BytesIO``-backed buffer. - """ - if self._original_fd >= 0: - return self._original_fd - return super().fileno() - - @property - def name(self) -> str: - return self._name - - @property - def mode(self) -> str: - return self._mode - - -def make_input_stream( - input: str | bytes | t.IO[t.Any] | None, charset: str -) -> t.BinaryIO: - # Is already an input stream. - if hasattr(input, "read"): - rv = _find_binary_reader(t.cast("t.IO[t.Any]", input)) - - if rv is not None: - return rv - - raise TypeError("Could not find binary reader for input stream.") - - if input is None: - input = b"" - elif isinstance(input, str): - input = input.encode(charset) - - return io.BytesIO(input) - - -class Result: - """Holds the captured result of an invoked CLI script. - - :param runner: The runner that created the result - :param stdout_bytes: The standard output as bytes. - :param stderr_bytes: The standard error as bytes. - :param output_bytes: A mix of ``stdout_bytes`` and ``stderr_bytes``, as the - user would see it in its terminal. - :param return_value: The value returned from the invoked command. - :param exit_code: The exit code as integer. - :param exception: The exception that happened if one did. - :param exc_info: Exception information (exception type, exception instance, - traceback type). - - .. versionchanged:: 8.2 - ``stderr_bytes`` no longer optional, ``output_bytes`` introduced and - ``mix_stderr`` has been removed. - - .. versionadded:: 8.0 - Added ``return_value``. - """ - - def __init__( - self, - runner: CliRunner, - stdout_bytes: bytes, - stderr_bytes: bytes, - output_bytes: bytes, - return_value: t.Any, - exit_code: int, - exception: BaseException | None, - exc_info: tuple[type[BaseException], BaseException, TracebackType] - | None = None, - ): - self.runner = runner - self.stdout_bytes = stdout_bytes - self.stderr_bytes = stderr_bytes - self.output_bytes = output_bytes - self.return_value = return_value - self.exit_code = exit_code - self.exception = exception - self.exc_info = exc_info - - @property - def output(self) -> str: - """The terminal output as unicode string, as the user would see it. - - .. versionchanged:: 8.2 - No longer a proxy for ``self.stdout``. Now has its own independent stream - that is mixing `` and ``, in the order they were written. - """ - return self.output_bytes.decode(self.runner.charset, "replace").replace( - "\r\n", "\n" - ) - - @property - def stdout(self) -> str: - """The standard output as unicode string.""" - return self.stdout_bytes.decode(self.runner.charset, "replace").replace( - "\r\n", "\n" - ) - - @property - def stderr(self) -> str: - """The standard error as unicode string. - - .. versionchanged:: 8.2 - No longer raise an exception, always returns the `` string. - """ - return self.stderr_bytes.decode(self.runner.charset, "replace").replace( - "\r\n", "\n" - ) - - def __repr__(self) -> str: - exc_str = repr(self.exception) if self.exception else "okay" - return f"<{type(self).__name__} {exc_str}>" - - -class CliRunner: - """The CLI runner provides functionality to invoke a Click command line - script for unittesting purposes in a isolated environment. This only - works in single-threaded systems without any concurrency as it changes the - global interpreter state. - - :param charset: the character set for the input and output data. - :param env: a dictionary with environment variables for overriding. - :param echo_stdin: if this is set to `True`, then reading from `` writes - to ``. This is useful for showing examples in - some circumstances. Note that regular prompts - will automatically echo the input. - :param catch_exceptions: Whether to catch any exceptions other than - ``SystemExit`` when running :meth:`~CliRunner.invoke`. - :param capture: Selects the output capture strategy. ``sys`` (default) - captures Python-level writes only and leaves - :meth:`sys.stdout.fileno` raising :exc:`io.UnsupportedOperation`, so - user code that calls :func:`os.dup2` on ``sys.stdout.fileno()`` cannot - clobber the host runner's stdout. ``fd`` redirects file descriptors - ``1`` and ``2`` via :func:`os.dup2` to a temporary file, also catching - output from stale stream references, C extensions, and subprocesses. - ``fd`` is not supported on Windows. - - .. versionchanged:: 8.4.0 - Added the ``capture`` parameter. The default ``sys`` mode no longer - exposes the original fd through :meth:`fileno`, reverting the change - introduced in ``8.3.3`` that broke Pytest's ``fd``-level capture - teardown. Use ``capture="fd"`` to restore that behavior with proper - isolation. :issue:`3384` - - .. versionchanged:: 8.2 - Added the ``catch_exceptions`` parameter. - - .. versionchanged:: 8.2 - ``mix_stderr`` parameter has been removed. - """ - - def __init__( - self, - charset: str = "utf-8", - env: cabc.Mapping[str, str | None] | None = None, - echo_stdin: bool = False, - catch_exceptions: bool = True, - capture: CaptureMode = "sys", - ) -> None: - if capture not in {"sys", "fd"}: - raise ValueError( - f"capture={capture!r} is not valid. Choose from 'sys' or 'fd'." - ) - if capture == "fd" and sys.platform == "win32": - raise ValueError( - f"capture={capture!r} is not supported on Windows. Use 'sys'." - ) - self.charset = charset - self.env: cabc.Mapping[str, str | None] = env or {} - self.echo_stdin = echo_stdin - self.catch_exceptions = catch_exceptions - self.capture: CaptureMode = capture - - def get_default_prog_name(self, cli: Command) -> str: - """Given a command object it will return the default program name - for it. The default is the `name` attribute or ``"root"`` if not - set. - """ - return cli.name or "root" - - def make_env( - self, overrides: cabc.Mapping[str, str | None] | None = None - ) -> cabc.Mapping[str, str | None]: - """Returns the environment overrides for invoking a script.""" - rv = dict(self.env) - if overrides: - rv.update(overrides) - return rv - - @contextlib.contextmanager - def isolation( - self, - input: str | bytes | t.IO[t.Any] | None = None, - env: cabc.Mapping[str, str | None] | None = None, - color: bool = False, - ) -> cabc.Iterator[tuple[io.BytesIO, io.BytesIO, io.BytesIO]]: - """A context manager that sets up the isolation for invoking of a - command line tool. This sets up `` with the given input data - and `os.environ` with the overrides from the given dictionary. - This also rebinds some internals in Click to be mocked (like the - prompt functionality). - - This is automatically done in the :meth:`invoke` method. - - :param input: the input stream to put into `sys.stdin`. - :param env: the environment overrides as dictionary. - :param color: whether the output should contain color codes. The - application can still override this explicitly. - - .. versionadded:: 8.2 - An additional output stream is returned, which is a mix of - `` and `` streams. - - .. versionchanged:: 8.2 - Always returns the `` stream. - - .. versionchanged:: 8.0 - `` is opened with ``errors="backslashreplace"`` - instead of the default ``"strict"``. - - .. versionchanged:: 4.0 - Added the ``color`` parameter. - """ - bytes_input = make_input_stream(input, self.charset) - echo_input = None - - old_stdin = sys.stdin - old_stdout = sys.stdout - old_stderr = sys.stderr - old_forced_width = formatting.FORCED_WIDTH - formatting.FORCED_WIDTH = 80 - - env = self.make_env(env) - - stream_mixer = StreamMixer() - - if self.echo_stdin: - bytes_input = echo_input = t.cast( - t.BinaryIO, EchoingStdin(bytes_input, stream_mixer.stdout) - ) - - sys.stdin = text_input = _NamedTextIOWrapper( - bytes_input, encoding=self.charset, name="", mode="r" - ) - - if self.echo_stdin: - # Force unbuffered reads, otherwise TextIOWrapper reads a - # large chunk which is echoed early. - text_input._CHUNK_SIZE = 1 # type: ignore - - sys.stdout = _NamedTextIOWrapper( - stream_mixer.stdout, - encoding=self.charset, - name="", - mode="w", - ) - - sys.stderr = _NamedTextIOWrapper( - stream_mixer.stderr, - encoding=self.charset, - name="", - mode="w", - errors="backslashreplace", - ) - - @_pause_echo(echo_input) # type: ignore - def visible_input(prompt: str | None = None) -> str: - sys.stdout.write(prompt or "") - try: - val = next(text_input).rstrip("\r\n") - except StopIteration as e: - raise EOFError() from e - sys.stdout.write(f"{val}\n") - sys.stdout.flush() - return val - - @_pause_echo(echo_input) # type: ignore - def hidden_input(prompt: str | None = None) -> str: - sys.stdout.write(f"{prompt or ''}\n") - sys.stdout.flush() - try: - return next(text_input).rstrip("\r\n") - except StopIteration as e: - raise EOFError() from e - - @_pause_echo(echo_input) # type: ignore - def _getchar(echo: bool) -> str: - char = sys.stdin.read(1) - - if echo: - sys.stdout.write(char) - - sys.stdout.flush() - return char - - default_color = color - - def should_strip_ansi( - stream: t.IO[t.Any] | None = None, color: bool | None = None - ) -> bool: - if color is None: - return not default_color - return not color - - old_visible_prompt_func = termui.visible_prompt_func - old_hidden_prompt_func = termui.hidden_prompt_func - old__getchar_func = termui._getchar - old_should_strip_ansi = utils.should_strip_ansi # type: ignore - old__compat_should_strip_ansi = _compat.should_strip_ansi - old_pdb_init = pdb.Pdb.__init__ - termui.visible_prompt_func = visible_input - termui.hidden_prompt_func = hidden_input - termui._getchar = _getchar - utils.should_strip_ansi = should_strip_ansi # type: ignore - _compat.should_strip_ansi = should_strip_ansi - - def _patched_pdb_init( - self: pdb.Pdb, - completekey: str = "tab", - stdin: t.IO[str] | None = None, - stdout: t.IO[str] | None = None, - **kwargs: t.Any, - ) -> None: - """Default ``pdb.Pdb`` to real terminal streams during - ``CliRunner`` isolation. - - Without this patch, ``pdb.Pdb.__init__`` inherits from - ``cmd.Cmd`` which falls back to ``sys.stdin``/``sys.stdout`` - when no explicit streams are provided. During isolation - those are ``BytesIO``-backed wrappers, so the debugger - reads from an empty buffer and writes to captured output, - making interactive debugging impossible. - - By defaulting to ``sys.__stdin__``/``sys.__stdout__`` (the - original terminal streams Python preserves regardless of - redirection), debuggers can interact with the user while - ``click.echo`` output is still captured normally. - - This covers ``pdb.set_trace()``, ``breakpoint()``, - ``pdb.post_mortem()``, and debuggers that subclass - ``pdb.Pdb`` (ipdb, pdbpp). Explicit ``stdin``/``stdout`` - arguments are honored and not overridden. Debuggers that - do not subclass ``pdb.Pdb`` (pudb, debugpy) are not - covered. - """ - if stdin is None: - stdin = sys.__stdin__ - if stdout is None: - stdout = sys.__stdout__ - old_pdb_init( - self, completekey=completekey, stdin=stdin, stdout=stdout, **kwargs - ) - - pdb.Pdb.__init__ = _patched_pdb_init # type: ignore[assignment] - - old_env = {} - try: - for key, value in env.items(): - old_env[key] = os.environ.get(key) - if value is None: - try: - del os.environ[key] - except Exception: - pass - else: - os.environ[key] = value - yield (stream_mixer.stdout, stream_mixer.stderr, stream_mixer.output) - finally: - for key, value in old_env.items(): - if value is None: - try: - del os.environ[key] - except Exception: - pass - else: - os.environ[key] = value - sys.stdout = old_stdout - sys.stderr = old_stderr - sys.stdin = old_stdin - termui.visible_prompt_func = old_visible_prompt_func - termui.hidden_prompt_func = old_hidden_prompt_func - termui._getchar = old__getchar_func - utils.should_strip_ansi = old_should_strip_ansi # type: ignore - _compat.should_strip_ansi = old__compat_should_strip_ansi - formatting.FORCED_WIDTH = old_forced_width - pdb.Pdb.__init__ = old_pdb_init # type: ignore[method-assign] - - def invoke( - self, - cli: Command, - args: str | cabc.Sequence[str] | None = None, - input: str | bytes | t.IO[t.Any] | None = None, - env: cabc.Mapping[str, str | None] | None = None, - catch_exceptions: bool | None = None, - color: bool = False, - **extra: t.Any, - ) -> Result: - """Invokes a command in an isolated environment. The arguments are - forwarded directly to the command line script, the `extra` keyword - arguments are passed to the :meth:`~clickpkg.Command.main` function of - the command. - - This returns a :class:`Result` object. - - :param cli: the command to invoke - :param args: the arguments to invoke. It may be given as an iterable - or a string. When given as string it will be interpreted - as a Unix shell command. More details at - :func:`shlex.split`. - :param input: the input data for `sys.stdin`. - :param env: the environment overrides. - :param catch_exceptions: Whether to catch any other exceptions than - ``SystemExit``. If :data:`None`, the value - from :class:`CliRunner` is used. - :param extra: the keyword arguments to pass to :meth:`main`. - :param color: whether the output should contain color codes. The - application can still override this explicitly. - - .. versionadded:: 8.2 - The result object has the ``output_bytes`` attribute with - the mix of ``stdout_bytes`` and ``stderr_bytes``, as the user would - see it in its terminal. - - .. versionchanged:: 8.2 - The result object always returns the ``stderr_bytes`` stream. - - .. versionchanged:: 8.0 - The result object has the ``return_value`` attribute with - the value returned from the invoked command. - - .. versionchanged:: 4.0 - Added the ``color`` parameter. - - .. versionchanged:: 3.0 - Added the ``catch_exceptions`` parameter. - - .. versionchanged:: 3.0 - The result object has the ``exc_info`` attribute with the - traceback if available. - """ - exc_info = None - if catch_exceptions is None: - catch_exceptions = self.catch_exceptions - - # Set up fd capture before isolation replaces sys.stdout and sys.stderr. - cap_out: _FDCapture | None = None - cap_err: _FDCapture | None = None - - if self.capture == "fd": - cap_out = _FDCapture(1) - cap_err = _FDCapture(2) - try: - cap_out.start() - cap_err.start() - except OSError: - cap_out = cap_err = None - - with self.isolation(input=input, env=env, color=color) as outstreams: - # Point the captured streams' fileno() at the saved (original) - # fd so that C-level consumers like faulthandler keep working - # while fd 1/2 are redirected to the capture tmpfile. - if cap_out is not None and cap_err is not None: - sys.stdout._original_fd = cap_out.saved_fd # type: ignore[union-attr] - sys.stderr._original_fd = cap_err.saved_fd # type: ignore[union-attr] - - return_value = None - exception: BaseException | None = None - exit_code = 0 - - if isinstance(args, str): - args = shlex.split(args) - - try: - prog_name = extra.pop("prog_name") - except KeyError: - prog_name = self.get_default_prog_name(cli) - - try: - return_value = cli.main(args=args or (), prog_name=prog_name, **extra) - except SystemExit as e: - exc_info = sys.exc_info() - e_code = t.cast("int | t.Any | None", e.code) - - if e_code is None: - e_code = 0 - - if e_code != 0: - exception = e - - if not isinstance(e_code, int): - sys.stdout.write(str(e_code)) - sys.stdout.write("\n") - e_code = 1 - - exit_code = e_code - - except Exception as e: - if not catch_exceptions: - raise - exception = e - exit_code = 1 - exc_info = sys.exc_info() - finally: - sys.stdout.flush() - sys.stderr.flush() - - # Stop fd capture and merge the captured bytes into - # the stdout/stderr BytesIO streams. BytesIOCopy mirrors - # those writes into outstreams[2] automatically. - if cap_out is not None and cap_err is not None: - fd_out = cap_out.stop() - fd_err = cap_err.stop() - if fd_out: - outstreams[0].write(fd_out) - if fd_err: - outstreams[1].write(fd_err) - - stdout = outstreams[0].getvalue() - stderr = outstreams[1].getvalue() - output = outstreams[2].getvalue() - - return Result( - runner=self, - stdout_bytes=stdout, - stderr_bytes=stderr, - output_bytes=output, - return_value=return_value, - exit_code=exit_code, - exception=exception, - exc_info=exc_info, # type: ignore - ) - - @contextlib.contextmanager - def isolated_filesystem( - self, temp_dir: str | os.PathLike[str] | None = None - ) -> cabc.Iterator[str]: - """A context manager that creates a temporary directory and - changes the current working directory to it. This isolates tests - that affect the contents of the CWD to prevent them from - interfering with each other. - - :param temp_dir: Create the temporary directory under this - directory. If given, the created directory is not removed - when exiting. - - .. versionchanged:: 8.0 - Added the ``temp_dir`` parameter. - """ - cwd = os.getcwd() - dt = tempfile.mkdtemp(dir=temp_dir) - os.chdir(dt) - - try: - yield dt - finally: - os.chdir(cwd) - - if temp_dir is None: - import shutil - - try: - shutil.rmtree(dt) - except OSError: - pass diff --git a/server/venv/Lib/site-packages/click/types.py b/server/venv/Lib/site-packages/click/types.py deleted file mode 100644 index 98c2d61..0000000 --- a/server/venv/Lib/site-packages/click/types.py +++ /dev/null @@ -1,1309 +0,0 @@ -from __future__ import annotations - -import abc -import collections.abc as cabc -import enum -import os -import stat -import sys -import typing as t -import uuid -from datetime import datetime -from gettext import gettext as _ -from gettext import ngettext - -from ._compat import _get_argv_encoding -from ._compat import open_stream -from .exceptions import BadParameter -from .utils import format_filename -from .utils import LazyFile -from .utils import safecall - -if t.TYPE_CHECKING: - import typing_extensions as te - - from .core import Context - from .core import Parameter - from .shell_completion import CompletionItem - -ParamTypeValue = t.TypeVar("ParamTypeValue") - - -class ParamTypeInfoDict(t.TypedDict): - param_type: str - name: str - - -class ParamType(t.Generic[ParamTypeValue], abc.ABC): - """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. - - .. versionchanged:: 8.4.0 - Now a generic abstract base class. Parameterize with the - converted value type (``ParamType[int]`` for an integer-returning - type) so that :meth:`convert` and downstream consumers carry the - narrowed return type. - """ - - is_composite: t.ClassVar[bool] = False - arity: t.ClassVar[int] = 1 - - #: the descriptive name of this type - name: str - - #: if a list of this type is expected and the value is pulled from a - #: string environment variable, this is what splits it up. `None` - #: means any whitespace. For all parameters the general rule is that - #: whitespace splits them up. The exception are paths and files which - #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on - #: Windows). - envvar_list_splitter: t.ClassVar[str | None] = None - - def to_info_dict(self) -> ParamTypeInfoDict: - """Gather information that could be useful for a tool generating - user-facing documentation. - - Use :meth:`click.Context.to_info_dict` to traverse the entire - CLI structure. - - .. versionadded:: 8.0 - """ - # The class name without the "ParamType" suffix. - param_type = type(self).__name__.partition("ParamType")[0] - param_type = param_type.partition("ParameterType")[0] - - # Custom subclasses might not remember to set a name. - if hasattr(self, "name"): - name = self.name - else: - name = param_type - - return {"param_type": param_type, "name": name} - - def __call__( - self, - value: t.Any, - param: Parameter | None = None, - ctx: Context | None = None, - ) -> ParamTypeValue | None: - if value is not None: - return self.convert(value, param, ctx) - return None - - def get_metavar(self, param: Parameter, ctx: Context) -> str | None: - """Returns the metavar default for this param if it provides one.""" - - def get_missing_message(self, param: Parameter, ctx: Context | None) -> str | None: - """Optionally might return extra information about a missing - parameter. - - .. versionadded:: 2.0 - """ - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> ParamTypeValue: - """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``. - """ - # The default returns the value as-is so subclasses that only customize - # metadata are not forced to redeclare ``convert``. - return t.cast("ParamTypeValue", value) - - def split_envvar_value(self, rv: str) -> cabc.Sequence[str]: - """Given a value from an environment variable this splits it up - into small chunks depending on the defined envvar list splitter. - - If the splitter is set to `None`, which means that whitespace splits, - then leading and trailing whitespace is ignored. Otherwise, leading - and trailing splitters usually lead to empty items being included. - """ - return (rv or "").split(self.envvar_list_splitter) - - def fail( - self, - message: str, - param: Parameter | None = None, - ctx: Context | None = None, - ) -> t.NoReturn: - """Helper method to fail with an invalid value message.""" - raise BadParameter(message, ctx=ctx, param=param) - - def shell_complete( - self, ctx: Context, param: Parameter, incomplete: str - ) -> list[CompletionItem]: - """Return a list of - :class:`~click.shell_completion.CompletionItem` objects for the - incomplete value. Most types do not provide completions, but - some do, and this allows custom types to provide custom - completions as well. - - :param ctx: Invocation context for this command. - :param param: The parameter that is requesting completion. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - return [] - - -class CompositeParamType(ParamType[ParamTypeValue]): - is_composite = True - - @property - @abc.abstractmethod - def arity(self) -> int: ... # type: ignore[override] - - -class FuncParamTypeInfoDict(ParamTypeInfoDict): - func: t.Callable[[t.Any], t.Any] - - -class FuncParamType(ParamType[ParamTypeValue]): - def __init__(self, func: t.Callable[[t.Any], ParamTypeValue]) -> None: - self.name: str = func.__name__ - self.func = func - - def to_info_dict(self) -> FuncParamTypeInfoDict: - return {"func": self.func, **super().to_info_dict()} - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> ParamTypeValue: - try: - return self.func(value) - except ValueError as exc: - message = str(exc) - - if not message: - try: - message = str(value) - except UnicodeError: - message = value.decode("utf-8", "replace") - - self.fail(message, param, ctx) - - -class UnprocessedParamType(ParamType[t.Any]): - name = "text" - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> t.Any: - return value - - def __repr__(self) -> str: - return "UNPROCESSED" - - -class StringParamType(ParamType[str]): - name = "text" - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> str: - if isinstance(value, bytes): - enc = _get_argv_encoding() - try: - value = value.decode(enc) - except UnicodeError: - fs_enc = sys.getfilesystemencoding() - if fs_enc != enc: - try: - value = value.decode(fs_enc) - except UnicodeError: - value = value.decode("utf-8", "replace") - else: - value = value.decode("utf-8", "replace") - return value # type: ignore[no-any-return] - return str(value) - - def __repr__(self) -> str: - return "STRING" - - -class ChoiceInfoDict(ParamTypeInfoDict): - choices: cabc.Sequence[t.Any] - case_sensitive: bool - - -class Choice(ParamType[ParamTypeValue], t.Generic[ParamTypeValue]): - """The choice type allows a value to be checked against a fixed set - of supported values. - - You may pass any iterable value which will be converted to a tuple - and thus will only be iterated once. - - The resulting value will always be one of the originally passed choices. - See :meth:`normalize_choice` for more info on the mapping of strings - to choices. See :ref:`choice-opts` for an example. - - :param case_sensitive: Set to false to make choices case - insensitive. Defaults to true. - - .. versionchanged:: 8.4.0 - Now generic in the choice value type. Parameterize with the type of - the choice values (``Choice[HashType]`` for an enum, ``Choice[str]`` - for plain strings) to enable type-checked consumers. - - .. versionchanged:: 8.2.0 - Non-``str`` ``choices`` are now supported. It can additionally be any - iterable. Before you were not recommended to pass anything but a list or - tuple. - - .. versionadded:: 8.2.0 - Choice normalization can be overridden via :meth:`normalize_choice`. - """ - - name = "choice" - - def __init__( - self, choices: cabc.Iterable[ParamTypeValue], case_sensitive: bool = True - ) -> None: - self.choices: cabc.Sequence[ParamTypeValue] = tuple(choices) - self.case_sensitive = case_sensitive - - def to_info_dict(self) -> ChoiceInfoDict: - return { - "choices": self.choices, - "case_sensitive": self.case_sensitive, - **super().to_info_dict(), - } - - def _normalized_mapping( - self, ctx: Context | None = None - ) -> cabc.Mapping[ParamTypeValue, str]: - """ - Returns mapping where keys are the original choices and the values are - the normalized values that are accepted via the command line. - - This is a simple wrapper around :meth:`normalize_choice`, use that - instead which is supported. - """ - return { - choice: self.normalize_choice( - choice=choice, - ctx=ctx, - ) - for choice in self.choices - } - - def normalize_choice(self, choice: ParamTypeValue, ctx: Context | None) -> str: - """ - Normalize a choice value, used to map a passed string to a choice. - Each choice must have a unique normalized value. - - By default uses :meth:`Context.token_normalize_func` and if not case - sensitive, convert it to a casefolded value. - - .. versionadded:: 8.2.0 - """ - normed_value = choice.name if isinstance(choice, enum.Enum) else str(choice) - - if ctx is not None and ctx.token_normalize_func is not None: - normed_value = ctx.token_normalize_func(normed_value) - - if not self.case_sensitive: - normed_value = normed_value.casefold() - - return normed_value - - def get_metavar(self, param: Parameter, ctx: Context) -> str | None: - if param.param_type_name == "option" and not param.show_choices: # type: ignore - choice_metavars = [ - convert_type(type(choice)).name.upper() for choice in self.choices - ] - choices_str = "|".join([*dict.fromkeys(choice_metavars)]) - else: - choices_str = "|".join( - [str(i) for i in self._normalized_mapping(ctx=ctx).values()] - ) - - # Use curly braces to indicate a required argument. - if param.required and param.param_type_name == "argument": - return f"{{{choices_str}}}" - - # Use square braces to indicate an option or optional argument. - return f"[{choices_str}]" - - def get_missing_message(self, param: Parameter, ctx: Context | None) -> str: - """ - Message shown when no choice is passed. - - .. versionchanged:: 8.2.0 Added ``ctx`` argument. - """ - return _("Choose from:\n\t{choices}").format( - choices=",\n\t".join(self._normalized_mapping(ctx=ctx).values()) - ) - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> ParamTypeValue: - """ - For a given value from the parser, normalize it and find its - matching normalized value in the list of choices. Then return the - matched "original" choice. - """ - normed_value = self.normalize_choice(choice=value, ctx=ctx) - normalized_mapping = self._normalized_mapping(ctx=ctx) - - try: - return next( - original - for original, normalized in normalized_mapping.items() - if normalized == normed_value - ) - except StopIteration: - self.fail( - self.get_invalid_choice_message(value=value, ctx=ctx), - param=param, - ctx=ctx, - ) - - def get_invalid_choice_message(self, value: t.Any, ctx: Context | None) -> str: - """Get the error message when the given choice is invalid. - - :param value: The invalid value. - - .. versionadded:: 8.2 - """ - choices_str = ", ".join(map(repr, self._normalized_mapping(ctx=ctx).values())) - return ngettext( - "{value!r} is not {choice}.", - "{value!r} is not one of {choices}.", - len(self.choices), - ).format(value=value, choice=choices_str, choices=choices_str) - - def __repr__(self) -> str: - return _("Choice({choices})").format(choices=list(self.choices)) - - def shell_complete( - self, ctx: Context, param: Parameter, incomplete: str - ) -> list[CompletionItem]: - """Complete choices that start with the incomplete value. - - :param ctx: Invocation context for this command. - :param param: The parameter that is requesting completion. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - str_choices = [self.normalize_choice(choice, ctx) for choice in 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 DateTimeInfoDict(ParamTypeInfoDict): - formats: cabc.Sequence[str] - - -class DateTime(ParamType[datetime]): - """The DateTime type converts date strings into `datetime` objects. - - The format strings which are checked are configurable, but default to some - common (non-timezone aware) ISO 8601 formats. - - When specifying *DateTime* formats, you should only pass a list or a tuple. - Other iterables, like generators, may lead to surprising results. - - The format strings are processed using ``datetime.strptime``, and this - consequently defines the format strings which are allowed. - - Parsing is tried using each format, in order, and the first format which - parses successfully is used. - - :param formats: A list or tuple of date format strings, in the order in - which they should be tried. Defaults to - ``'%Y-%m-%d'``, ``'%Y-%m-%dT%H:%M:%S'``, - ``'%Y-%m-%d %H:%M:%S'``. - """ - - name = "datetime" - - def __init__(self, formats: cabc.Sequence[str] | None = None): - self.formats: cabc.Sequence[str] = formats or [ - "%Y-%m-%d", - "%Y-%m-%dT%H:%M:%S", - "%Y-%m-%d %H:%M:%S", - ] - - def to_info_dict(self) -> DateTimeInfoDict: - return {"formats": self.formats, **super().to_info_dict()} - - def get_metavar(self, param: Parameter, ctx: Context) -> str | None: - return f"[{'|'.join(self.formats)}]" - - def _try_to_convert_date(self, value: t.Any, format: str) -> datetime | None: - try: - return datetime.strptime(value, format) - except ValueError: - return None - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> datetime: - 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[ParamTypeValue]): - _number_class: t.Callable[[t.Any], ParamTypeValue] - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> ParamTypeValue: - 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 NumberRangeInfoDict(ParamTypeInfoDict): - min: float | None - max: float | None - min_open: bool - max_open: bool - clamp: bool - - -class _NumberRangeBase(_NumberParamTypeBase[ParamTypeValue]): - def __init__( - self, - min: float | None = None, - max: float | None = None, - min_open: bool = False, - max_open: bool = False, - clamp: bool = False, - ) -> None: - self.min = min - self.max = max - self.min_open = min_open - self.max_open = max_open - self.clamp = clamp - - def to_info_dict(self) -> NumberRangeInfoDict: - return { - "min": self.min, - "max": self.max, - "min_open": self.min_open, - "max_open": self.max_open, - "clamp": self.clamp, - **super().to_info_dict(), - } - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> ParamTypeValue: - import operator - - rv = super().convert(value, param, ctx) - min = self.min - max = self.max - lt_min: bool = min is not None and ( - operator.le if self.min_open else operator.lt - )(rv, min) # type: ignore[arg-type] - gt_max: bool = max is not None and ( - operator.ge if self.max_open else operator.gt - )(rv, max) # type: ignore[arg-type] - - if self.clamp: - if min is not None and lt_min: - return self._clamp(min, 1, self.min_open) # type: ignore[arg-type] - - if max is not None and gt_max: - return self._clamp(max, -1, self.max_open) # type: ignore[arg-type] - - 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 - - @abc.abstractmethod - def _clamp( - self, bound: ParamTypeValue, dir: t.Literal[1, -1], open: bool - ) -> ParamTypeValue: - """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. - """ - ... - - 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[int]): - name = "integer" - _number_class = int - - def __repr__(self) -> str: - return "INT" - - -class IntRange(_NumberRangeBase[int], 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(self, bound: int, dir: t.Literal[1, -1], open: bool) -> int: - if not open: - return bound - - return bound + dir - - -class FloatParamType(_NumberParamTypeBase[float]): - name = "float" - _number_class = float - - def __repr__(self) -> str: - return "FLOAT" - - -class FloatRange(_NumberRangeBase[float], FloatParamType): - """Restrict a :data:`click.FLOAT` value to a range of accepted - values. See :ref:`ranges`. - - If ``min`` or ``max`` are not passed, any value is accepted in that - direction. If ``min_open`` or ``max_open`` are enabled, the - corresponding boundary is not included in the range. - - If ``clamp`` is enabled, a value outside the range is clamped to the - boundary instead of failing. This is not supported if either - boundary is marked ``open``. - - .. versionchanged:: 8.0 - Added the ``min_open`` and ``max_open`` parameters. - """ - - name = "float range" - - def __init__( - self, - min: float | None = None, - max: float | None = None, - min_open: bool = False, - max_open: bool = False, - clamp: bool = False, - ) -> None: - super().__init__( - min=min, max=max, min_open=min_open, max_open=max_open, clamp=clamp - ) - - if (min_open or max_open) and clamp: - raise TypeError("Clamping is not supported for open bounds.") - - def _clamp(self, bound: float, dir: t.Literal[1, -1], open: bool) -> float: - if not open: - return bound - - # Could use math.nextafter here, but clamping an - # open float range doesn't seem to be particularly useful. It's - # left up to the user to write a callback to do it if needed. - raise RuntimeError("Clamping is not supported for open bounds.") - - -class BoolParamType(ParamType[bool]): - name = "boolean" - - bool_states: dict[str, bool] = { - "1": True, - "0": False, - "yes": True, - "no": False, - "true": True, - "false": False, - "on": True, - "off": False, - "t": True, - "f": False, - "y": True, - "n": False, - # Absence of value is considered False. - "": False, - } - """A mapping of string values to boolean states. - - Mapping is inspired by :py:attr:`configparser.ConfigParser.BOOLEAN_STATES` - and extends it. - - .. caution:: - String values are lower-cased, as the ``str_to_bool`` comparison function - below is case-insensitive. - - .. warning:: - The mapping is not exhaustive, and does not cover all possible boolean strings - representations. It will remains as it is to avoid endless bikeshedding. - - Future work my be considered to make this mapping user-configurable from public - API. - """ - - @staticmethod - def str_to_bool(value: str | bool) -> bool | None: - """Convert a string to a boolean value. - - If the value is already a boolean, it is returned as-is. If the value is a - string, it is stripped of whitespaces and lower-cased, then checked against - the known boolean states pre-defined in the `BoolParamType.bool_states` mapping - above. - - Returns `None` if the value does not match any known boolean state. - """ - if isinstance(value, bool): - return value - return BoolParamType.bool_states.get(value.strip().lower()) - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> bool: - normalized = self.str_to_bool(value) - if normalized is None: - self.fail( - _( - "{value!r} is not a valid boolean. Recognized values: {states}" - ).format(value=value, states=", ".join(sorted(self.bool_states))), - param, - ctx, - ) - return normalized - - def __repr__(self) -> str: - return "BOOL" - - -class UUIDParameterType(ParamType[uuid.UUID]): - name = "uuid" - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> uuid.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 FileInfoDict(ParamTypeInfoDict): - mode: str - encoding: str | None - - -class File(ParamType[t.IO[t.Any]]): - """Declares a parameter to be a file for reading or writing. The file - is automatically closed once the context tears down (after the command - finished working). - - Files can be opened for reading or writing. The special value ``-`` - indicates stdin or stdout depending on the mode. - - By default, the file is opened for reading text data, but it can also be - opened in binary mode or for writing. The encoding parameter can be used - to force a specific encoding. - - The `lazy` flag controls if the file should be opened immediately or upon - first IO. The default is to be non-lazy for standard input and output - streams as well as files opened for reading, `lazy` otherwise. When opening a - file lazily for reading, it is still opened temporarily for validation, but - will not be held open until first IO. lazy is mainly useful when opening - for writing to avoid creating the file until it is needed. - - Files can also be opened atomically in which case all writes go into a - separate file in the same folder and upon completion the file will - be moved over to the original location. This is useful if a file - regularly read by other users is modified. - - See :ref:`file-args` for more information. - - .. versionchanged:: 2.0 - Added the ``atomic`` parameter. - """ - - name = "filename" - envvar_list_splitter: t.ClassVar[str] = os.path.pathsep - - def __init__( - self, - mode: str = "r", - encoding: str | None = None, - errors: str | None = "strict", - lazy: bool | None = None, - atomic: bool = False, - ) -> None: - self.mode = mode - self.encoding = encoding - self.errors = errors - self.lazy = lazy - self.atomic = atomic - - def to_info_dict(self) -> FileInfoDict: - return { - "mode": self.mode, - "encoding": self.encoding, - **super().to_info_dict(), - } - - def resolve_lazy_flag(self, value: str | os.PathLike[str]) -> bool: - if self.lazy is not None: - return self.lazy - if os.fspath(value) == "-": - return False - elif "w" in self.mode: - return True - return False - - def convert( - self, - value: str | os.PathLike[str] | t.IO[t.Any], - param: Parameter | None, - ctx: Context | None, - ) -> t.IO[t.Any]: - if _is_file_like(value): - return value - - value = t.cast("str | os.PathLike[str]", value) - - try: - lazy = self.resolve_lazy_flag(value) - - if lazy: - lf = LazyFile( - value, self.mode, self.encoding, self.errors, atomic=self.atomic - ) - - if ctx is not None: - ctx.call_on_close(lf.close_intelligently) - - return t.cast("t.IO[t.Any]", lf) - - f, should_close = open_stream( - value, self.mode, self.encoding, self.errors, atomic=self.atomic - ) - - # If a context is provided, we automatically close the file - # at the end of the context execution (or flush out). If a - # context does not exist, it's the caller's responsibility to - # properly close the file. This for instance happens when the - # type is used with prompts. - if ctx is not None: - if should_close: - ctx.call_on_close(safecall(f.close)) - else: - ctx.call_on_close(safecall(f.flush)) - - return f - except OSError as e: - self.fail( - f"'{format_filename(value)}': {e.strerror}", - param, - ctx, - ) - - def shell_complete( - self, ctx: Context, param: Parameter, incomplete: str - ) -> list[CompletionItem]: - """Return a special completion marker that tells the completion - system to use the shell to provide file path completions. - - :param ctx: Invocation context for this command. - :param param: The parameter that is requesting completion. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - return [CompletionItem(incomplete, type="file")] - - -def _is_file_like(value: t.Any) -> te.TypeGuard[t.IO[t.Any]]: - return hasattr(value, "read") or hasattr(value, "write") - - -class PathInfoDict(ParamTypeInfoDict): - exists: bool - file_okay: bool - dir_okay: bool - writable: bool - readable: bool - allow_dash: bool - - -class Path(ParamType[str | bytes | os.PathLike[str]]): - """The ``Path`` type is similar to the :class:`File` type, but - returns the filename instead of an open file. Various checks can be - enabled to validate the type of file and permissions. - - :param exists: The file or directory needs to exist for the value to - be valid. If this is not set to ``True``, and the file does not - exist, then all further checks are silently skipped. - :param file_okay: Allow a file as a value. - :param dir_okay: Allow a directory as a value. - :param readable: if true, a readable check is performed. - :param writable: if true, a writable check is performed. - :param executable: if true, an executable check is performed. - :param resolve_path: Make the value absolute and resolve any - symlinks. A ``~`` is not expanded, as this is supposed to be - done by the shell only. - :param allow_dash: Allow a single dash as a value, which indicates - a standard stream (but does not open it). Use - :func:`~click.open_file` to handle opening this value. - :param path_type: Convert the incoming path value to this type. If - ``None``, keep Python's default, which is ``str``. Useful to - convert to :class:`pathlib.Path`. - - .. versionchanged:: 8.1 - Added the ``executable`` parameter. - - .. versionchanged:: 8.0 - Allow passing ``path_type=pathlib.Path``. - - .. versionchanged:: 6.0 - Added the ``allow_dash`` parameter. - """ - - envvar_list_splitter: t.ClassVar[str] = os.path.pathsep - - def __init__( - self, - exists: bool = False, - file_okay: bool = True, - dir_okay: bool = True, - writable: bool = False, - readable: bool = True, - resolve_path: bool = False, - allow_dash: bool = False, - path_type: type[t.Any] | None = None, - executable: bool = False, - ): - self.exists = exists - self.file_okay = file_okay - self.dir_okay = dir_okay - self.readable = readable - self.writable = writable - self.executable = executable - self.resolve_path = resolve_path - self.allow_dash = allow_dash - self.type = path_type - - if self.file_okay and not self.dir_okay: - self.name: str = _("file") - elif self.dir_okay and not self.file_okay: - self.name = _("directory") - else: - self.name = _("path") - - def to_info_dict(self) -> PathInfoDict: - return { - "exists": self.exists, - "file_okay": self.file_okay, - "dir_okay": self.dir_okay, - "writable": self.writable, - "readable": self.readable, - "allow_dash": self.allow_dash, - **super().to_info_dict(), - } - - def coerce_path_result( - self, value: str | os.PathLike[str] - ) -> str | bytes | os.PathLike[str]: - if self.type is not None and not isinstance(value, self.type): - if self.type is str: - return os.fsdecode(value) - elif self.type is bytes: - return os.fsencode(value) - else: - return t.cast("os.PathLike[str]", self.type(value)) - - return value - - def convert( - self, - value: str | os.PathLike[str], - param: Parameter | None, - ctx: Context | None, - ) -> str | bytes | os.PathLike[str]: - rv = value - - is_dash = self.file_okay and self.allow_dash and rv in (b"-", "-") - - if not is_dash: - if self.resolve_path: - rv = os.path.realpath(rv) - - try: - st = os.stat(rv) - except OSError: - if not self.exists: - return self.coerce_path_result(rv) - self.fail( - _("{name} {filename!r} does not exist.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - if not self.file_okay and stat.S_ISREG(st.st_mode): - self.fail( - _("{name} {filename!r} is a file.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - if not self.dir_okay and stat.S_ISDIR(st.st_mode): - self.fail( - _("{name} {filename!r} is a directory.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - if self.readable and not os.access(rv, os.R_OK): - self.fail( - _("{name} {filename!r} is not readable.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - if self.writable and not os.access(rv, os.W_OK): - self.fail( - _("{name} {filename!r} is not writable.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - if self.executable and not os.access(value, os.X_OK): - self.fail( - _("{name} {filename!r} is not executable.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - return self.coerce_path_result(rv) - - def shell_complete( - self, ctx: Context, param: Parameter, incomplete: str - ) -> list[CompletionItem]: - """Return a special completion marker that tells the completion - system to use the shell to provide path completions for only - directories or any paths. - - :param ctx: Invocation context for this command. - :param param: The parameter that is requesting completion. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - type = "dir" if self.dir_okay and not self.file_okay else "file" - return [CompletionItem(incomplete, type=type)] - - -class TupleInfoDict(ParamTypeInfoDict): - types: cabc.Sequence[ParamTypeInfoDict] - - -class Tuple(CompositeParamType[tuple[t.Any, ...]]): - """The default behavior of Click is to apply a type on a value directly. - This works well in most cases, except for when `nargs` is set to a fixed - count and different types should be used for different items. In this - case the :class:`Tuple` type can be used. This type can only be used - if `nargs` is set to a fixed number. - - For more information see :ref:`tuple-type`. - - This can be selected by using a Python tuple literal as a type. - - :param types: a list of types that should be used for the tuple items. - """ - - def __init__(self, types: cabc.Sequence[type[t.Any] | ParamType[t.Any]]) -> None: - self.types: cabc.Sequence[ParamType[t.Any]] = [convert_type(ty) for ty in types] - - def to_info_dict(self) -> TupleInfoDict: - return { - "types": [ty.to_info_dict() for ty in self.types], - **super().to_info_dict(), - } - - @property - def name(self) -> str: # type: ignore[override] - return f"<{' '.join(ty.name for ty in self.types)}>" - - @property - def arity(self) -> int: # type: ignore[override] - return len(self.types) - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> tuple[t.Any, ...]: - len_type = len(self.types) - len_value = len(value) - - if len_value != len_type: - self.fail( - ngettext( - "{len_type} values are required, but {len_value} was given.", - "{len_type} values are required, but {len_value} were given.", - len_value, - ).format(len_type=len_type, len_value=len_value), - param=param, - ctx=ctx, - ) - - return tuple( - ty(x, param, ctx) for ty, x in zip(self.types, value, strict=False) - ) - - -def _guess_type( - ty: type[t.Any] | ParamType[t.Any] | None, - default: t.Any | None, -) -> type[t.Any] | tuple[type[t.Any], ...] | ParamType[t.Any] | None: - """Infer a type from *ty* or *default*. - - Returns *ty* unchanged when it is not ``None``. Otherwise inspects - *default* to produce a ``type``, a ``tuple`` of types (for tuple - defaults), or ``None``. - """ - if ty is not None: - return ty - - if default is None: - return None - - if not isinstance(default, (tuple, list)): - return type(default) - - # If the default is empty, return None so convert_type falls - # through to STRING. - if not default: - return None - - item = default[0] - - # A sequence of iterables needs to detect the inner types. - # Can't call convert_type recursively because that would - # incorrectly unwind the tuple to a single type. - if isinstance(item, (tuple, list)): - return tuple(map(type, item)) - - return type(item) - - -@t.overload -def convert_type(ty: None, default: None = None) -> StringParamType: ... - - -@t.overload -def convert_type( - ty: type[t.Any] | ParamType[t.Any], default: t.Any | None = None -) -> ParamType[t.Any]: ... - - -@t.overload -def convert_type( - ty: t.Any | None, default: t.Any | None = None -) -> ParamType[t.Any]: ... - - -def convert_type( - ty: t.Any | None = None, default: t.Any | None = None -) -> ParamType[t.Any]: - """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 = _guess_type(ty, default) - is_guessed = guessed is not ty - - if isinstance(guessed, tuple): - return Tuple(guessed) - - if isinstance(guessed, ParamType): - return guessed - - if guessed is str or guessed is None: - return STRING - - if guessed is int: - return INT - - if guessed is float: - return FLOAT - - if guessed is bool: - return BOOL - - if is_guessed: - return STRING - - if __debug__: - try: - if issubclass(guessed, ParamType): - raise AssertionError( - f"Attempted to use an uninstantiated parameter type ({guessed})." - ) - except TypeError: - # guessed is an instance (correct), so issubclass fails. - pass - - return FuncParamType(guessed) - - -#: 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 provided. -#: -#: .. versionadded:: 4.0 -UNPROCESSED = UnprocessedParamType() - -#: A unicode string parameter type which is the implicit default. This -#: can also be selected by using ``str`` as type. -STRING = StringParamType() - -#: An integer parameter. This can also be selected by using ``int`` as -#: type. -INT = IntParamType() - -#: A floating point value parameter. This can also be selected by using -#: ``float`` as type. -FLOAT = FloatParamType() - -#: A boolean parameter. This is the default for boolean flags. This can -#: also be selected by using ``bool`` as a type. -BOOL = BoolParamType() - -#: A UUID parameter. -UUID = UUIDParameterType() - - -class OptionHelpExtra(t.TypedDict, total=False): - envvars: tuple[str, ...] - default: str - range: str - required: str diff --git a/server/venv/Lib/site-packages/click/utils.py b/server/venv/Lib/site-packages/click/utils.py deleted file mode 100644 index 67922b8..0000000 --- a/server/venv/Lib/site-packages/click/utils.py +++ /dev/null @@ -1,641 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import os -import re -import sys -import typing as t -from functools import update_wrapper -from gettext import gettext as _ -from types import ModuleType -from types import TracebackType - -from ._compat import _default_text_stderr -from ._compat import _default_text_stdout -from ._compat import _find_binary_writer -from ._compat import auto_wrap_for_ansi -from ._compat import binary_streams -from ._compat import open_stream -from ._compat import should_strip_ansi -from ._compat import strip_ansi -from ._compat import text_streams -from ._compat import WIN -from .globals import resolve_color_default - -if t.TYPE_CHECKING: - import typing_extensions as te - - P = te.ParamSpec("P") - -R = t.TypeVar("R") - - -def _posixify(name: str) -> str: - return "-".join(name.split()).lower() - - -def safecall(func: t.Callable[P, R]) -> t.Callable[P, R | None]: - """Wraps a function so that it swallows exceptions.""" - - def wrapper(*args: P.args, **kwargs: P.kwargs) -> R | None: - try: - return func(*args, **kwargs) - except Exception: - pass - return None - - return update_wrapper(wrapper, func) - - -def make_str(value: t.Any) -> str: - """Converts a value into a valid string.""" - if isinstance(value, bytes): - try: - return value.decode(sys.getfilesystemencoding()) - except UnicodeError: - return value.decode("utf-8", "replace") - return str(value) - - -def make_default_short_help(help: str, max_length: int = 45) -> str: - """Returns a condensed version of help string. - - :meta private: - """ - # 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. - """ - - name: str - mode: str - encoding: str | None - errors: str | None - atomic: bool - _f: t.IO[t.Any] | None - should_close: bool - - def __init__( - self, - filename: str | os.PathLike[str], - mode: str = "r", - encoding: str | None = None, - errors: str | None = "strict", - atomic: bool = False, - ) -> None: - self.name = os.fspath(filename) - self.mode = mode - self.encoding = encoding - self.errors = errors - self.atomic = atomic - - if self.name == "-": - self._f, self.should_close = open_stream(filename, mode, encoding, errors) - else: - if "r" in mode: - # Open and close the file in case we're opening it for - # reading so that we can catch at least some errors in - # some cases early. - open(filename, mode).close() - self._f = None - self.should_close = True - - def __getattr__(self, name: str) -> t.Any: - return getattr(self.open(), name) - - def __repr__(self) -> str: - if self._f is not None: - return repr(self._f) - return f"" - - def open(self) -> t.IO[t.Any]: - """Opens the file if it's not yet open. This call might fail with - a :exc:`FileError`. Not handling this error will produce an error - that Click shows. - """ - if self._f is not None: - return self._f - try: - rv, self.should_close = open_stream( - self.name, self.mode, self.encoding, self.errors, atomic=self.atomic - ) - except OSError as e: - from .exceptions import FileError - - raise FileError(self.name, hint=e.strerror) from e - self._f = rv - return rv - - def close(self) -> None: - """Closes the underlying file, no matter what.""" - if self._f is not None: - self._f.close() - - def close_intelligently(self) -> None: - """This function only closes the file if it was opened by the lazy - file wrapper. For instance this will never close stdin. - """ - if self.should_close: - self.close() - - def __enter__(self) -> LazyFile: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - tb: TracebackType | None, - ) -> None: - self.close_intelligently() - - def __iter__(self) -> cabc.Iterator[t.AnyStr]: - self.open() - return iter(self._f) # type: ignore - - -class KeepOpenFile: - _file: t.IO[t.Any] - - def __init__(self, file: t.IO[t.Any]) -> 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: type[BaseException] | None, - exc_value: BaseException | None, - tb: TracebackType | None, - ) -> None: - pass - - def __repr__(self) -> str: - return repr(self._file) - - def __iter__(self) -> cabc.Iterator[t.AnyStr]: - return iter(self._file) - - -def echo( - message: object = None, - file: t.IO[t.Any] | None = None, - nl: bool = True, - err: bool = False, - color: bool | None = None, -) -> None: - """Print a message and newline to stdout or a file. This should be - used instead of :func:`print` because it provides better support - for different data, files, and environments. - - Compared to :func:`print`, this does the following: - - - Ensures that the output encoding is not misconfigured on Linux. - - Supports Unicode in the Windows console. - - Supports writing to binary outputs, and supports writing bytes - to text outputs. - - Supports colors and styles on Windows. - - Removes ANSI color and style codes if the output does not look - like an interactive terminal. - - Always flushes the output. - - :param message: The string or bytes to output. Other objects are - converted to strings. - :param file: The file to write to. Defaults to ``stdout``. - :param err: Write to ``stderr`` instead of ``stdout``. - :param nl: Print a newline after the message. Enabled by default. - :param color: Force showing or hiding colors and other styles. By - default Click will remove color if the output does not look like - an interactive terminal. - - .. versionchanged:: 6.0 - Support Unicode output on the Windows console. Click does not - modify ``sys.stdout``, so ``sys.stdout.write()`` and ``print()`` - will still not support Unicode. - - .. versionchanged:: 4.0 - Added the ``color`` parameter. - - .. versionadded:: 3.0 - Added the ``err`` parameter. - - .. versionchanged:: 2.0 - Support colors on Windows if colorama is installed. - """ - if file is None: - if err: - file = _default_text_stderr() - else: - file = _default_text_stdout() - - # There are no standard streams attached to write to. For example, - # pythonw on Windows. - if file is None: - return - - match message: - case str() | bytes() | bytearray(): - out = message - case None: - out = "" - case _: - out = str(message) - - if nl: - if isinstance(out, str): - out += "\n" - else: - out += b"\n" - - if not out: - file.flush() - return - - # If there is a message and the value looks like bytes, we manually - # need to find the binary stream and write the message in there. - # This is done separately so that most stream types will work as you - # would expect. Eg: you can write to StringIO for other cases. - if isinstance(out, (bytes, bytearray)): - binary_file = _find_binary_writer(file) - if binary_file is not None: - file.flush() - binary_file.write(out) - binary_file.flush() - return - - # ANSI style code support. For no message or bytes, nothing happens. - # When outputting to a file instead of a terminal, strip codes. - else: - color = resolve_color_default(color) - - if should_strip_ansi(file, color): - out = strip_ansi(out) - elif WIN: - if auto_wrap_for_ansi is not None: - file = auto_wrap_for_ansi(file, color) # type: ignore - elif not color: - out = strip_ansi(out) - - file.write(out) # type: ignore - file.flush() - - -def get_binary_stream(name: t.Literal["stdin", "stdout", "stderr"]) -> t.BinaryIO: - """Returns a system stream for byte processing. - - :param name: the name of the stream to open. Valid names are ``'stdin'``, - ``'stdout'`` and ``'stderr'`` - """ - opener = binary_streams.get(name) - if opener is None: - raise TypeError(_("Unknown standard stream '{name}'").format(name=name)) - return opener() - - -def get_text_stream( - name: t.Literal["stdin", "stdout", "stderr"], - encoding: str | None = None, - errors: str | None = "strict", -) -> t.TextIO: - """Returns a system stream for text processing. This usually returns - a wrapped stream around a binary stream returned from - :func:`get_binary_stream` but it also can take shortcuts for already - correctly configured streams. - - :param name: the name of the stream to open. Valid names are ``'stdin'``, - ``'stdout'`` and ``'stderr'`` - :param encoding: overrides the detected default encoding. - :param errors: overrides the default error mode. - """ - opener = text_streams.get(name) - if opener is None: - raise TypeError(_("Unknown standard stream '{name}'").format(name=name)) - return opener(encoding, errors) - - -def open_file( - filename: str | os.PathLike[str], - mode: str = "r", - encoding: str | None = None, - errors: str | None = "strict", - lazy: bool = False, - atomic: bool = False, -) -> t.IO[t.Any]: - """Open a file, with extra behavior to handle ``'-'`` to indicate - a standard stream, lazy open on write, and atomic write. Similar to - the behavior of the :class:`~click.File` param type. - - If ``'-'`` is given to open ``stdout`` or ``stdin``, the stream is - wrapped so that using it in a context manager will not close it. - This makes it possible to use the function without accidentally - closing a standard stream: - - .. code-block:: python - - with open_file(filename) as f: - ... - - :param filename: The name or Path of the file to open, or ``'-'`` for - ``stdin``/``stdout``. - :param mode: The mode in which to open the file. - :param encoding: The encoding to decode or encode a file opened in - text mode. - :param errors: The error handling mode. - :param lazy: Wait to open the file until it is accessed. For read - mode, the file is temporarily opened to raise access errors - early, then closed until it is read again. - :param atomic: Write to a temporary file and replace the given file - on close. - - .. versionadded:: 3.0 - """ - if lazy: - return t.cast( - "t.IO[t.Any]", LazyFile(filename, mode, encoding, errors, atomic=atomic) - ) - - f, should_close = open_stream(filename, mode, encoding, errors, atomic=atomic) - - if not should_close: - f = t.cast("t.IO[t.Any]", KeepOpenFile(f)) - - return f - - -def format_filename( - filename: str | bytes | os.PathLike[str] | os.PathLike[bytes], - shorten: bool = False, -) -> str: - """Format a filename as a string for display. Ensures the filename can be - displayed by replacing any invalid bytes or surrogate escapes in the name - with the replacement character ``�``. - - Invalid bytes or surrogate escapes will raise an error when written to a - stream with ``errors="strict"``. This will typically happen with ``stdout`` - when the locale is something like ``en_GB.UTF-8``. - - Many scenarios *are* safe to write surrogates though, due to PEP 538 and - PEP 540, including: - - - Writing to ``stderr``, which uses ``errors="backslashreplace"``. - - The system has ``LANG=C.UTF-8``, ``C``, or ``POSIX``. Python opens - stdout and stderr with ``errors="surrogateescape"``. - - None of ``LANG/LC_*`` are set. Python assumes ``LANG=C.UTF-8``. - - Python is started in UTF-8 mode with ``PYTHONUTF8=1`` or ``-X utf8``. - Python opens stdout and stderr with ``errors="surrogateescape"``. - - :param filename: formats a filename for UI display. This will also convert - the filename into unicode without failing. - :param shorten: this optionally shortens the filename to strip of the - path that leads up to it. - """ - if shorten: - filename = os.path.basename(filename) - else: - filename = os.fspath(filename) - - if isinstance(filename, bytes): - filename = filename.decode(sys.getfilesystemencoding(), "replace") - else: - filename = filename.encode("utf-8", "surrogateescape").decode( - "utf-8", "replace" - ) - - return filename - - -def get_app_dir(app_name: str, roaming: bool = True, force_posix: bool = False) -> str: - r"""Returns the config folder for the application. The default behavior - is to return whatever is most appropriate for the operating system. - - To give you an idea, for an app called ``"Foo Bar"``, something like - the following folders could be returned: - - Mac OS X: - ``~/Library/Application Support/Foo Bar`` - Mac OS X (POSIX): - ``~/.foo-bar`` - Unix: - ``~/.config/foo-bar`` - Unix (POSIX): - ``~/.foo-bar`` - Windows (roaming): - ``C:\Users\\AppData\Roaming\Foo Bar`` - Windows (not roaming): - ``C:\Users\\AppData\Local\Foo Bar`` - - .. versionadded:: 2.0 - - :param app_name: the application name. This should be properly capitalized - and can contain whitespace. - :param roaming: controls if the folder should be roaming or not on Windows. - Has no effect otherwise. - :param force_posix: if this is set to `True` then on any POSIX system the - folder will be stored in the home folder with a leading - dot instead of the XDG config home or darwin's - application support folder. - """ - if WIN: - key = "APPDATA" if roaming else "LOCALAPPDATA" - folder = os.environ.get(key) - if folder is None: - folder = os.path.expanduser("~") - return os.path.join(folder, app_name) - if force_posix: - return os.path.join(os.path.expanduser(f"~/.{_posixify(app_name)}")) - if sys.platform == "darwin": - return os.path.join( - os.path.expanduser("~/Library/Application Support"), app_name - ) - return os.path.join( - os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")), - _posixify(app_name), - ) - - -class PacifyFlushWrapper: - """This wrapper is used to catch and suppress BrokenPipeErrors resulting - from ``.flush()`` being called on broken pipe during the shutdown/final-GC - of the Python interpreter. Notably ``.flush()`` is always called on - ``sys.stdout`` and ``sys.stderr``. So as to have minimal impact on any - other cleanup code, and the case where the underlying file is not a broken - pipe, all calls and attributes are proxied. - """ - - wrapped: t.IO[t.Any] - - def __init__(self, wrapped: t.IO[t.Any]) -> None: - self.wrapped = wrapped - - def flush(self) -> None: - try: - self.wrapped.flush() - except OSError as e: - import errno - - if e.errno != errno.EPIPE: - raise - - def __getattr__(self, attr: str) -> t.Any: - return getattr(self.wrapped, attr) - - -def _detect_program_name( - path: str | None = None, _main: ModuleType | None = None -) -> str: - """Determine the command used to run the program, for use in help - text. If a file or entry point was executed, the file name is - returned. If ``python -m`` was used to execute a module or package, - ``python -m name`` is returned. - - This doesn't try to be too precise, the goal is to give a concise - name for help text. Files are only shown as their name without the - path. ``python`` is only shown for modules, and the full path to - ``sys.executable`` is not shown. - - :param path: The Python file being executed. Python puts this in - ``sys.argv[0]``, which is used by default. - :param _main: The ``__main__`` module. This should only be passed - during internal testing. - - .. versionadded:: 8.0 - Based on command args detection in the Werkzeug reloader. - - :meta private: - """ - if _main is None: - _main = sys.modules["__main__"] - - if not path: - path = sys.argv[0] - - # The value of __package__ indicates how Python was called. It may - # not exist if a setuptools script is installed as an egg. It may be - # set incorrectly for entry points created with pip on Windows. - # It is set to "" inside a Shiv or PEX zipapp. - if getattr(_main, "__package__", None) in {None, ""} or ( - os.name == "nt" - and _main.__package__ == "" - and not os.path.exists(path) - and os.path.exists(f"{path}.exe") - ): - # Executed a file, like "python app.py". - return os.path.basename(path) - - # Executed a module, like "python -m example". - # Rewritten by Python from "-m script" to "/path/to/script.py". - # Need to look at main module to determine how it was executed. - py_module = t.cast(str, _main.__package__) - name = os.path.splitext(os.path.basename(path))[0] - - # A submodule like "example.cli". - if name != "__main__": - py_module = f"{py_module}.{name}" - - return f"python -m {py_module.lstrip('.')}" - - -def _expand_args( - args: cabc.Iterable[str], - *, - user: bool = True, - env: bool = True, - glob_recursive: bool = True, -) -> list[str]: - """Simulate Unix shell expansion with Python functions. - - See :func:`glob.glob`, :func:`os.path.expanduser`, and - :func:`os.path.expandvars`. - - This is intended for use on Windows, where the shell does not do any - expansion. It may not exactly match what a Unix shell would do. - - :param args: List of command line arguments to expand. - :param user: Expand user home directory. - :param env: Expand environment variables. - :param glob_recursive: ``**`` matches directories recursively. - - .. versionchanged:: 8.1 - Invalid glob patterns are treated as empty expansions rather - than raising an error. - - .. versionadded:: 8.0 - - :meta private: - """ - from glob import glob - - out = [] - - for arg in args: - if user: - arg = os.path.expanduser(arg) - - if env: - arg = os.path.expandvars(arg) - - try: - matches = glob(arg, recursive=glob_recursive) - except re.error: - matches = [] - - if not matches: - out.append(arg) - else: - out.extend(matches) - - return out diff --git a/server/venv/Lib/site-packages/colorama-0.4.6.dist-info/INSTALLER b/server/venv/Lib/site-packages/colorama-0.4.6.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/server/venv/Lib/site-packages/colorama-0.4.6.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/server/venv/Lib/site-packages/colorama-0.4.6.dist-info/METADATA b/server/venv/Lib/site-packages/colorama-0.4.6.dist-info/METADATA deleted file mode 100644 index a1b5c57..0000000 --- a/server/venv/Lib/site-packages/colorama-0.4.6.dist-info/METADATA +++ /dev/null @@ -1,441 +0,0 @@ -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/server/venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD b/server/venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD deleted file mode 100644 index b85b5b7..0000000 --- a/server/venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD +++ /dev/null @@ -1,31 +0,0 @@ -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-313.pyc,, -colorama/__pycache__/ansi.cpython-313.pyc,, -colorama/__pycache__/ansitowin32.cpython-313.pyc,, -colorama/__pycache__/initialise.cpython-313.pyc,, -colorama/__pycache__/win32.cpython-313.pyc,, -colorama/__pycache__/winterm.cpython-313.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-313.pyc,, -colorama/tests/__pycache__/ansi_test.cpython-313.pyc,, -colorama/tests/__pycache__/ansitowin32_test.cpython-313.pyc,, -colorama/tests/__pycache__/initialise_test.cpython-313.pyc,, -colorama/tests/__pycache__/isatty_test.cpython-313.pyc,, -colorama/tests/__pycache__/utils.cpython-313.pyc,, -colorama/tests/__pycache__/winterm_test.cpython-313.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/server/venv/Lib/site-packages/colorama-0.4.6.dist-info/WHEEL b/server/venv/Lib/site-packages/colorama-0.4.6.dist-info/WHEEL deleted file mode 100644 index d79189f..0000000 --- a/server/venv/Lib/site-packages/colorama-0.4.6.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.11.1 -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any diff --git a/server/venv/Lib/site-packages/colorama-0.4.6.dist-info/licenses/LICENSE.txt b/server/venv/Lib/site-packages/colorama-0.4.6.dist-info/licenses/LICENSE.txt deleted file mode 100644 index 3105888..0000000 --- a/server/venv/Lib/site-packages/colorama-0.4.6.dist-info/licenses/LICENSE.txt +++ /dev/null @@ -1,27 +0,0 @@ -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/server/venv/Lib/site-packages/colorama/__init__.py b/server/venv/Lib/site-packages/colorama/__init__.py deleted file mode 100644 index 383101c..0000000 --- a/server/venv/Lib/site-packages/colorama/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# 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/server/venv/Lib/site-packages/colorama/ansi.py b/server/venv/Lib/site-packages/colorama/ansi.py deleted file mode 100644 index 11ec695..0000000 --- a/server/venv/Lib/site-packages/colorama/ansi.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. -''' -This module generates ANSI character codes to printing colors to terminals. -See: http://en.wikipedia.org/wiki/ANSI_escape_code -''' - -CSI = '\033[' -OSC = '\033]' -BEL = '\a' - - -def code_to_chars(code): - return CSI + str(code) + 'm' - -def set_title(title): - return OSC + '2;' + title + BEL - -def clear_screen(mode=2): - return CSI + str(mode) + 'J' - -def clear_line(mode=2): - return CSI + str(mode) + 'K' - - -class AnsiCodes(object): - def __init__(self): - # the subclasses declare class attributes which are numbers. - # Upon instantiation we define instance attributes, which are the same - # as the class attributes but wrapped with the ANSI escape sequence - for name in dir(self): - if not name.startswith('_'): - value = getattr(self, name) - setattr(self, name, code_to_chars(value)) - - -class AnsiCursor(object): - def UP(self, n=1): - return CSI + str(n) + 'A' - def DOWN(self, n=1): - return CSI + str(n) + 'B' - def FORWARD(self, n=1): - return CSI + str(n) + 'C' - def BACK(self, n=1): - return CSI + str(n) + 'D' - def POS(self, x=1, y=1): - return CSI + str(y) + ';' + str(x) + 'H' - - -class AnsiFore(AnsiCodes): - BLACK = 30 - RED = 31 - GREEN = 32 - YELLOW = 33 - BLUE = 34 - MAGENTA = 35 - CYAN = 36 - WHITE = 37 - RESET = 39 - - # These are fairly well supported, but not part of the standard. - LIGHTBLACK_EX = 90 - LIGHTRED_EX = 91 - LIGHTGREEN_EX = 92 - LIGHTYELLOW_EX = 93 - LIGHTBLUE_EX = 94 - LIGHTMAGENTA_EX = 95 - LIGHTCYAN_EX = 96 - LIGHTWHITE_EX = 97 - - -class AnsiBack(AnsiCodes): - BLACK = 40 - RED = 41 - GREEN = 42 - YELLOW = 43 - BLUE = 44 - MAGENTA = 45 - CYAN = 46 - WHITE = 47 - RESET = 49 - - # These are fairly well supported, but not part of the standard. - LIGHTBLACK_EX = 100 - LIGHTRED_EX = 101 - LIGHTGREEN_EX = 102 - LIGHTYELLOW_EX = 103 - LIGHTBLUE_EX = 104 - LIGHTMAGENTA_EX = 105 - LIGHTCYAN_EX = 106 - LIGHTWHITE_EX = 107 - - -class AnsiStyle(AnsiCodes): - BRIGHT = 1 - DIM = 2 - NORMAL = 22 - RESET_ALL = 0 - -Fore = AnsiFore() -Back = AnsiBack() -Style = AnsiStyle() -Cursor = AnsiCursor() diff --git a/server/venv/Lib/site-packages/colorama/ansitowin32.py b/server/venv/Lib/site-packages/colorama/ansitowin32.py deleted file mode 100644 index abf209e..0000000 --- a/server/venv/Lib/site-packages/colorama/ansitowin32.py +++ /dev/null @@ -1,277 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. -import re -import sys -import os - -from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style, BEL -from .winterm import enable_vt_processing, WinTerm, WinColor, WinStyle -from .win32 import windll, winapi_test - - -winterm = None -if windll is not None: - winterm = WinTerm() - - -class StreamWrapper(object): - ''' - Wraps a stream (such as stdout), acting as a transparent proxy for all - attribute access apart from method 'write()', which is delegated to our - Converter instance. - ''' - def __init__(self, wrapped, converter): - # double-underscore everything to prevent clashes with names of - # attributes on the wrapped stream object. - self.__wrapped = wrapped - self.__convertor = converter - - def __getattr__(self, name): - return getattr(self.__wrapped, name) - - def __enter__(self, *args, **kwargs): - # special method lookup bypasses __getattr__/__getattribute__, see - # https://stackoverflow.com/questions/12632894/why-doesnt-getattr-work-with-exit - # thus, contextlib magic methods are not proxied via __getattr__ - return self.__wrapped.__enter__(*args, **kwargs) - - def __exit__(self, *args, **kwargs): - return self.__wrapped.__exit__(*args, **kwargs) - - def __setstate__(self, state): - self.__dict__ = state - - def __getstate__(self): - return self.__dict__ - - def write(self, text): - self.__convertor.write(text) - - def isatty(self): - stream = self.__wrapped - if 'PYCHARM_HOSTED' in os.environ: - if stream is not None and (stream is sys.__stdout__ or stream is sys.__stderr__): - return True - try: - stream_isatty = stream.isatty - except AttributeError: - return False - else: - return stream_isatty() - - @property - def closed(self): - stream = self.__wrapped - try: - return stream.closed - # AttributeError in the case that the stream doesn't support being closed - # ValueError for the case that the stream has already been detached when atexit runs - except (AttributeError, ValueError): - return True - - -class AnsiToWin32(object): - ''' - Implements a 'write()' method which, on Windows, will strip ANSI character - sequences from the text, and if outputting to a tty, will convert them into - win32 function calls. - ''' - ANSI_CSI_RE = re.compile('\001?\033\\[((?:\\d|;)*)([a-zA-Z])\002?') # Control Sequence Introducer - ANSI_OSC_RE = re.compile('\001?\033\\]([^\a]*)(\a)\002?') # Operating System Command - - def __init__(self, wrapped, convert=None, strip=None, autoreset=False): - # The wrapped stream (normally sys.stdout or sys.stderr) - self.wrapped = wrapped - - # should we reset colors to defaults after every .write() - self.autoreset = autoreset - - # create the proxy wrapping our output stream - self.stream = StreamWrapper(wrapped, self) - - on_windows = os.name == 'nt' - # We test if the WinAPI works, because even if we are on Windows - # we may be using a terminal that doesn't support the WinAPI - # (e.g. Cygwin Terminal). In this case it's up to the terminal - # to support the ANSI codes. - conversion_supported = on_windows and winapi_test() - try: - fd = wrapped.fileno() - except Exception: - fd = -1 - system_has_native_ansi = not on_windows or enable_vt_processing(fd) - have_tty = not self.stream.closed and self.stream.isatty() - need_conversion = conversion_supported and not system_has_native_ansi - - # should we strip ANSI sequences from our output? - if strip is None: - strip = need_conversion or not have_tty - self.strip = strip - - # should we should convert ANSI sequences into win32 calls? - if convert is None: - convert = need_conversion and have_tty - self.convert = convert - - # dict of ansi codes to win32 functions and parameters - self.win32_calls = self.get_win32_calls() - - # are we wrapping stderr? - self.on_stderr = self.wrapped is sys.stderr - - def should_wrap(self): - ''' - True if this class is actually needed. If false, then the output - stream will not be affected, nor will win32 calls be issued, so - wrapping stdout is not actually required. This will generally be - False on non-Windows platforms, unless optional functionality like - autoreset has been requested using kwargs to init() - ''' - return self.convert or self.strip or self.autoreset - - def get_win32_calls(self): - if self.convert and winterm: - return { - AnsiStyle.RESET_ALL: (winterm.reset_all, ), - AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT), - AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL), - AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL), - AnsiFore.BLACK: (winterm.fore, WinColor.BLACK), - AnsiFore.RED: (winterm.fore, WinColor.RED), - AnsiFore.GREEN: (winterm.fore, WinColor.GREEN), - AnsiFore.YELLOW: (winterm.fore, WinColor.YELLOW), - AnsiFore.BLUE: (winterm.fore, WinColor.BLUE), - AnsiFore.MAGENTA: (winterm.fore, WinColor.MAGENTA), - AnsiFore.CYAN: (winterm.fore, WinColor.CYAN), - AnsiFore.WHITE: (winterm.fore, WinColor.GREY), - AnsiFore.RESET: (winterm.fore, ), - AnsiFore.LIGHTBLACK_EX: (winterm.fore, WinColor.BLACK, True), - AnsiFore.LIGHTRED_EX: (winterm.fore, WinColor.RED, True), - AnsiFore.LIGHTGREEN_EX: (winterm.fore, WinColor.GREEN, True), - AnsiFore.LIGHTYELLOW_EX: (winterm.fore, WinColor.YELLOW, True), - AnsiFore.LIGHTBLUE_EX: (winterm.fore, WinColor.BLUE, True), - AnsiFore.LIGHTMAGENTA_EX: (winterm.fore, WinColor.MAGENTA, True), - AnsiFore.LIGHTCYAN_EX: (winterm.fore, WinColor.CYAN, True), - AnsiFore.LIGHTWHITE_EX: (winterm.fore, WinColor.GREY, True), - AnsiBack.BLACK: (winterm.back, WinColor.BLACK), - AnsiBack.RED: (winterm.back, WinColor.RED), - AnsiBack.GREEN: (winterm.back, WinColor.GREEN), - AnsiBack.YELLOW: (winterm.back, WinColor.YELLOW), - AnsiBack.BLUE: (winterm.back, WinColor.BLUE), - AnsiBack.MAGENTA: (winterm.back, WinColor.MAGENTA), - AnsiBack.CYAN: (winterm.back, WinColor.CYAN), - AnsiBack.WHITE: (winterm.back, WinColor.GREY), - AnsiBack.RESET: (winterm.back, ), - AnsiBack.LIGHTBLACK_EX: (winterm.back, WinColor.BLACK, True), - AnsiBack.LIGHTRED_EX: (winterm.back, WinColor.RED, True), - AnsiBack.LIGHTGREEN_EX: (winterm.back, WinColor.GREEN, True), - AnsiBack.LIGHTYELLOW_EX: (winterm.back, WinColor.YELLOW, True), - AnsiBack.LIGHTBLUE_EX: (winterm.back, WinColor.BLUE, True), - AnsiBack.LIGHTMAGENTA_EX: (winterm.back, WinColor.MAGENTA, True), - AnsiBack.LIGHTCYAN_EX: (winterm.back, WinColor.CYAN, True), - AnsiBack.LIGHTWHITE_EX: (winterm.back, WinColor.GREY, True), - } - return dict() - - def write(self, text): - if self.strip or self.convert: - self.write_and_convert(text) - else: - self.wrapped.write(text) - self.wrapped.flush() - if self.autoreset: - self.reset_all() - - - def reset_all(self): - if self.convert: - self.call_win32('m', (0,)) - elif not self.strip and not self.stream.closed: - self.wrapped.write(Style.RESET_ALL) - - - def write_and_convert(self, text): - ''' - Write the given text to our wrapped stream, stripping any ANSI - sequences from the text, and optionally converting them into win32 - calls. - ''' - cursor = 0 - text = self.convert_osc(text) - for match in self.ANSI_CSI_RE.finditer(text): - start, end = match.span() - self.write_plain_text(text, cursor, start) - self.convert_ansi(*match.groups()) - cursor = end - self.write_plain_text(text, cursor, len(text)) - - - def write_plain_text(self, text, start, end): - if start < end: - self.wrapped.write(text[start:end]) - self.wrapped.flush() - - - def convert_ansi(self, paramstring, command): - if self.convert: - params = self.extract_params(command, paramstring) - self.call_win32(command, params) - - - def extract_params(self, command, paramstring): - if command in 'Hf': - params = tuple(int(p) if len(p) != 0 else 1 for p in paramstring.split(';')) - while len(params) < 2: - # defaults: - params = params + (1,) - else: - params = tuple(int(p) for p in paramstring.split(';') if len(p) != 0) - if len(params) == 0: - # defaults: - if command in 'JKm': - params = (0,) - elif command in 'ABCD': - params = (1,) - - return params - - - def call_win32(self, command, params): - if command == 'm': - for param in params: - if param in self.win32_calls: - func_args = self.win32_calls[param] - func = func_args[0] - args = func_args[1:] - kwargs = dict(on_stderr=self.on_stderr) - func(*args, **kwargs) - elif command in 'J': - winterm.erase_screen(params[0], on_stderr=self.on_stderr) - elif command in 'K': - winterm.erase_line(params[0], on_stderr=self.on_stderr) - elif command in 'Hf': # cursor position - absolute - winterm.set_cursor_position(params, on_stderr=self.on_stderr) - elif command in 'ABCD': # cursor position - relative - n = params[0] - # A - up, B - down, C - forward, D - back - x, y = {'A': (0, -n), 'B': (0, n), 'C': (n, 0), 'D': (-n, 0)}[command] - winterm.cursor_adjust(x, y, on_stderr=self.on_stderr) - - - def convert_osc(self, text): - for match in self.ANSI_OSC_RE.finditer(text): - start, end = match.span() - text = text[:start] + text[end:] - paramstring, command = match.groups() - if command == BEL: - if paramstring.count(";") == 1: - params = paramstring.split(";") - # 0 - change title and icon (we will only change title) - # 1 - change icon (we don't support this) - # 2 - change title - if params[0] in '02': - winterm.set_title(params[1]) - return text - - - def flush(self): - self.wrapped.flush() diff --git a/server/venv/Lib/site-packages/colorama/initialise.py b/server/venv/Lib/site-packages/colorama/initialise.py deleted file mode 100644 index d5fd4b7..0000000 --- a/server/venv/Lib/site-packages/colorama/initialise.py +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. -import atexit -import contextlib -import sys - -from .ansitowin32 import AnsiToWin32 - - -def _wipe_internal_state_for_tests(): - global orig_stdout, orig_stderr - orig_stdout = None - orig_stderr = None - - global wrapped_stdout, wrapped_stderr - wrapped_stdout = None - wrapped_stderr = None - - global atexit_done - atexit_done = False - - global fixed_windows_console - fixed_windows_console = False - - try: - # no-op if it wasn't registered - atexit.unregister(reset_all) - except AttributeError: - # python 2: no atexit.unregister. Oh well, we did our best. - pass - - -def reset_all(): - if AnsiToWin32 is not None: # Issue #74: objects might become None at exit - AnsiToWin32(orig_stdout).reset_all() - - -def init(autoreset=False, convert=None, strip=None, wrap=True): - - if not wrap and any([autoreset, convert, strip]): - raise ValueError('wrap=False conflicts with any other arg=True') - - global wrapped_stdout, wrapped_stderr - global orig_stdout, orig_stderr - - orig_stdout = sys.stdout - orig_stderr = sys.stderr - - if sys.stdout is None: - wrapped_stdout = None - else: - sys.stdout = wrapped_stdout = \ - wrap_stream(orig_stdout, convert, strip, autoreset, wrap) - if sys.stderr is None: - wrapped_stderr = None - else: - sys.stderr = wrapped_stderr = \ - wrap_stream(orig_stderr, convert, strip, autoreset, wrap) - - global atexit_done - if not atexit_done: - atexit.register(reset_all) - atexit_done = True - - -def deinit(): - if orig_stdout is not None: - sys.stdout = orig_stdout - if orig_stderr is not None: - sys.stderr = orig_stderr - - -def just_fix_windows_console(): - global fixed_windows_console - - if sys.platform != "win32": - return - if fixed_windows_console: - return - if wrapped_stdout is not None or wrapped_stderr is not None: - # Someone already ran init() and it did stuff, so we won't second-guess them - return - - # On newer versions of Windows, AnsiToWin32.__init__ will implicitly enable the - # native ANSI support in the console as a side-effect. We only need to actually - # replace sys.stdout/stderr if we're in the old-style conversion mode. - new_stdout = AnsiToWin32(sys.stdout, convert=None, strip=None, autoreset=False) - if new_stdout.convert: - sys.stdout = new_stdout - new_stderr = AnsiToWin32(sys.stderr, convert=None, strip=None, autoreset=False) - if new_stderr.convert: - sys.stderr = new_stderr - - fixed_windows_console = True - -@contextlib.contextmanager -def colorama_text(*args, **kwargs): - init(*args, **kwargs) - try: - yield - finally: - deinit() - - -def reinit(): - if wrapped_stdout is not None: - sys.stdout = wrapped_stdout - if wrapped_stderr is not None: - sys.stderr = wrapped_stderr - - -def wrap_stream(stream, convert, strip, autoreset, wrap): - if wrap: - wrapper = AnsiToWin32(stream, - convert=convert, strip=strip, autoreset=autoreset) - if wrapper.should_wrap(): - stream = wrapper.stream - return stream - - -# Use this for initial setup as well, to reduce code duplication -_wipe_internal_state_for_tests() diff --git a/server/venv/Lib/site-packages/colorama/tests/__init__.py b/server/venv/Lib/site-packages/colorama/tests/__init__.py deleted file mode 100644 index 8c5661e..0000000 --- a/server/venv/Lib/site-packages/colorama/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. diff --git a/server/venv/Lib/site-packages/colorama/tests/ansi_test.py b/server/venv/Lib/site-packages/colorama/tests/ansi_test.py deleted file mode 100644 index 0a20c80..0000000 --- a/server/venv/Lib/site-packages/colorama/tests/ansi_test.py +++ /dev/null @@ -1,76 +0,0 @@ -# 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/server/venv/Lib/site-packages/colorama/tests/ansitowin32_test.py b/server/venv/Lib/site-packages/colorama/tests/ansitowin32_test.py deleted file mode 100644 index 91ca551..0000000 --- a/server/venv/Lib/site-packages/colorama/tests/ansitowin32_test.py +++ /dev/null @@ -1,294 +0,0 @@ -# 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/server/venv/Lib/site-packages/colorama/tests/initialise_test.py b/server/venv/Lib/site-packages/colorama/tests/initialise_test.py deleted file mode 100644 index 89f9b07..0000000 --- a/server/venv/Lib/site-packages/colorama/tests/initialise_test.py +++ /dev/null @@ -1,189 +0,0 @@ -# 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/server/venv/Lib/site-packages/colorama/tests/isatty_test.py b/server/venv/Lib/site-packages/colorama/tests/isatty_test.py deleted file mode 100644 index 0f84e4b..0000000 --- a/server/venv/Lib/site-packages/colorama/tests/isatty_test.py +++ /dev/null @@ -1,57 +0,0 @@ -# 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/server/venv/Lib/site-packages/colorama/tests/utils.py b/server/venv/Lib/site-packages/colorama/tests/utils.py deleted file mode 100644 index 472fafb..0000000 --- a/server/venv/Lib/site-packages/colorama/tests/utils.py +++ /dev/null @@ -1,49 +0,0 @@ -# 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/server/venv/Lib/site-packages/colorama/tests/winterm_test.py b/server/venv/Lib/site-packages/colorama/tests/winterm_test.py deleted file mode 100644 index d0955f9..0000000 --- a/server/venv/Lib/site-packages/colorama/tests/winterm_test.py +++ /dev/null @@ -1,131 +0,0 @@ -# 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/server/venv/Lib/site-packages/colorama/win32.py b/server/venv/Lib/site-packages/colorama/win32.py deleted file mode 100644 index 841b0e2..0000000 --- a/server/venv/Lib/site-packages/colorama/win32.py +++ /dev/null @@ -1,180 +0,0 @@ -# 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/server/venv/Lib/site-packages/colorama/winterm.py b/server/venv/Lib/site-packages/colorama/winterm.py deleted file mode 100644 index aad867e..0000000 --- a/server/venv/Lib/site-packages/colorama/winterm.py +++ /dev/null @@ -1,195 +0,0 @@ -# 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/server/venv/Lib/site-packages/comerr64.dll b/server/venv/Lib/site-packages/comerr64.dll deleted file mode 100644 index a067ea55766f03fe2ae185867109e3880a062bcc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31360 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 None: - from .ipython import load_ipython_extension - - load_ipython_extension(ipython) - - -def get_cli_string( - path: Optional[str] = None, - action: Optional[str] = None, - key: Optional[str] = None, - value: Optional[str] = None, - quote: Optional[str] = None, -): - """Returns a string suitable for running as a shell script. - - Useful for converting a arguments passed to a fabric task - to be passed to a `local` or `run` command. - """ - command = ["dotenv"] - if quote: - command.append(f"-q {quote}") - if path: - command.append(f"-f {path}") - if action: - command.append(action) - if key: - command.append(key) - if value: - if " " in value: - command.append(f'"{value}"') - else: - command.append(value) - - return " ".join(command).strip() - - -__all__ = [ - "get_cli_string", - "load_dotenv", - "dotenv_values", - "get_key", - "set_key", - "unset_key", - "find_dotenv", - "load_ipython_extension", -] diff --git a/server/venv/Lib/site-packages/dotenv/__main__.py b/server/venv/Lib/site-packages/dotenv/__main__.py deleted file mode 100644 index 3977f55..0000000 --- a/server/venv/Lib/site-packages/dotenv/__main__.py +++ /dev/null @@ -1,6 +0,0 @@ -"""Entry point for cli, enables execution with `python -m dotenv`""" - -from .cli import cli - -if __name__ == "__main__": - cli() diff --git a/server/venv/Lib/site-packages/dotenv/cli.py b/server/venv/Lib/site-packages/dotenv/cli.py deleted file mode 100644 index 47eec04..0000000 --- a/server/venv/Lib/site-packages/dotenv/cli.py +++ /dev/null @@ -1,236 +0,0 @@ -import json -import os -import shlex -import sys -from contextlib import contextmanager -from typing import IO, Any, Dict, Iterator, List, Optional - -if sys.platform == "win32": - from subprocess import Popen - -try: - import click -except ImportError: - sys.stderr.write( - "It seems python-dotenv is not installed with cli option. \n" - 'Run pip install "python-dotenv[cli]" to fix this.' - ) - sys.exit(1) - -from .main import dotenv_values, set_key, unset_key -from .version import __version__ - - -def enumerate_env() -> Optional[str]: - """ - Return a path for the ${pwd}/.env file. - - If pwd does not exist, return None. - """ - try: - cwd = os.getcwd() - except FileNotFoundError: - return None - path = os.path.join(cwd, ".env") - return path - - -@click.group() -@click.option( - "-f", - "--file", - default=enumerate_env(), - type=click.Path(file_okay=True), - help="Location of the .env file, defaults to .env file in current working directory.", -) -@click.option( - "-q", - "--quote", - default="always", - type=click.Choice(["always", "never", "auto"]), - help="Whether to quote or not the variable values. Default mode is always. This does not affect parsing.", -) -@click.option( - "-e", - "--export", - default=False, - type=click.BOOL, - help="Whether to write the dot file as an executable bash script.", -) -@click.version_option(version=__version__) -@click.pass_context -def cli(ctx: click.Context, file: Any, quote: Any, export: Any) -> None: - """This script is used to set, get or unset values from a .env file.""" - ctx.obj = {"QUOTE": quote, "EXPORT": export, "FILE": file} - - -@contextmanager -def stream_file(path: os.PathLike) -> Iterator[IO[str]]: - """ - Open a file and yield the corresponding (decoded) stream. - - Exits with error code 2 if the file cannot be opened. - """ - - try: - with open(path) as stream: - yield stream - except OSError as exc: - print(f"Error opening env file: {exc}", file=sys.stderr) - sys.exit(2) - - -@cli.command(name="list") -@click.pass_context -@click.option( - "--format", - "output_format", - default="simple", - type=click.Choice(["simple", "json", "shell", "export"]), - help="The format in which to display the list. Default format is simple, " - "which displays name=value without quotes.", -) -def list_values(ctx: click.Context, output_format: str) -> None: - """Display all the stored key/value.""" - file = ctx.obj["FILE"] - - with stream_file(file) as stream: - values = dotenv_values(stream=stream) - - if output_format == "json": - click.echo(json.dumps(values, indent=2, sort_keys=True)) - else: - prefix = "export " if output_format == "export" else "" - for k in sorted(values): - v = values[k] - if v is not None: - if output_format in ("export", "shell"): - v = shlex.quote(v) - click.echo(f"{prefix}{k}={v}") - - -@cli.command(name="set") -@click.pass_context -@click.argument("key", required=True) -@click.argument("value", required=True) -def set_value(ctx: click.Context, key: Any, value: Any) -> None: - """ - Store the given key/value. - - This doesn't follow symlinks, to avoid accidentally modifying a file at a - potentially untrusted path. - """ - - file = ctx.obj["FILE"] - quote = ctx.obj["QUOTE"] - export = ctx.obj["EXPORT"] - success, key, value = set_key(file, key, value, quote, export) - if success: - click.echo(f"{key}={value}") - else: - sys.exit(1) - - -@cli.command() -@click.pass_context -@click.argument("key", required=True) -def get(ctx: click.Context, key: Any) -> None: - """Retrieve the value for the given key.""" - file = ctx.obj["FILE"] - - with stream_file(file) as stream: - values = dotenv_values(stream=stream) - - stored_value = values.get(key) - if stored_value: - click.echo(stored_value) - else: - sys.exit(1) - - -@cli.command() -@click.pass_context -@click.argument("key", required=True) -def unset(ctx: click.Context, key: Any) -> None: - """ - Removes the given key. - - This doesn't follow symlinks, to avoid accidentally modifying a file at a - potentially untrusted path. - """ - file = ctx.obj["FILE"] - quote = ctx.obj["QUOTE"] - success, key = unset_key(file, key, quote) - if success: - click.echo(f"Successfully removed {key}") - else: - sys.exit(1) - - -@cli.command( - context_settings={ - "allow_extra_args": True, - "allow_interspersed_args": False, - "ignore_unknown_options": True, - } -) -@click.pass_context -@click.option( - "--override/--no-override", - default=True, - help="Override variables from the environment file with those from the .env file.", -) -@click.argument("commandline", nargs=-1, type=click.UNPROCESSED) -def run(ctx: click.Context, override: bool, commandline: tuple[str, ...]) -> None: - """Run command with environment variables present.""" - file = ctx.obj["FILE"] - if not os.path.isfile(file): - raise click.BadParameter( - f"Invalid value for '-f' \"{file}\" does not exist.", ctx=ctx - ) - dotenv_as_dict = { - k: v - for (k, v) in dotenv_values(file).items() - if v is not None and (override or k not in os.environ) - } - - if not commandline: - click.echo("No command given.") - sys.exit(1) - - run_command([*commandline, *ctx.args], dotenv_as_dict) - - -def run_command(command: List[str], env: Dict[str, str]) -> None: - """Replace the current process with the specified command. - - Replaces the current process with the specified command and the variables from `env` - added in the current environment variables. - - Parameters - ---------- - command: List[str] - The command and it's parameters - env: Dict - The additional environment variables - - Returns - ------- - None - This function does not return any value. It replaces the current process with the new one. - - """ - # copy the current environment variables and add the vales from - # `env` - cmd_env = os.environ.copy() - cmd_env.update(env) - - if sys.platform == "win32": - # execvpe on Windows returns control immediately - # rather than once the command has finished. - p = Popen(command, universal_newlines=True, bufsize=0, shell=False, env=cmd_env) - _, _ = p.communicate() - - sys.exit(p.returncode) - else: - os.execvpe(command[0], args=command, env=cmd_env) diff --git a/server/venv/Lib/site-packages/dotenv/ipython.py b/server/venv/Lib/site-packages/dotenv/ipython.py deleted file mode 100644 index 4e7edbb..0000000 --- a/server/venv/Lib/site-packages/dotenv/ipython.py +++ /dev/null @@ -1,50 +0,0 @@ -from IPython.core.magic import Magics, line_magic, magics_class # type: ignore -from IPython.core.magic_arguments import ( - argument, - magic_arguments, - parse_argstring, -) # type: ignore - -from .main import find_dotenv, load_dotenv - - -@magics_class -class IPythonDotEnv(Magics): - @magic_arguments() - @argument( - "-o", - "--override", - action="store_true", - help="Indicate to override existing variables", - ) - @argument( - "-v", - "--verbose", - action="store_true", - help="Indicate function calls to be verbose", - ) - @argument( - "dotenv_path", - nargs="?", - type=str, - default=".env", - help="Search in increasingly higher folders for the `dotenv_path`", - ) - @line_magic - def dotenv(self, line): - args = parse_argstring(self.dotenv, line) - # Locate the .env file - dotenv_path = args.dotenv_path - try: - dotenv_path = find_dotenv(dotenv_path, True, True) - except IOError: - print("cannot find .env file") - return - - # Load the .env file - load_dotenv(dotenv_path, verbose=args.verbose, override=args.override) - - -def load_ipython_extension(ipython): - """Register the %dotenv magic.""" - ipython.register_magics(IPythonDotEnv) diff --git a/server/venv/Lib/site-packages/dotenv/main.py b/server/venv/Lib/site-packages/dotenv/main.py deleted file mode 100644 index 48e5245..0000000 --- a/server/venv/Lib/site-packages/dotenv/main.py +++ /dev/null @@ -1,480 +0,0 @@ -import io -import logging -import os -import pathlib -import stat -import sys -import tempfile -from collections import OrderedDict -from contextlib import contextmanager -from typing import IO, Dict, Iterable, Iterator, Mapping, Optional, Tuple, Union - -from .parser import Binding, parse_stream -from .variables import parse_variables - -# A type alias for a string path to be used for the paths in this file. -# These paths may flow to `open()` and `os.replace()`. -StrPath = Union[str, "os.PathLike[str]"] - -logger = logging.getLogger(__name__) - - -def _load_dotenv_disabled() -> bool: - """ - Determine if dotenv loading has been disabled. - """ - if "PYTHON_DOTENV_DISABLED" not in os.environ: - return False - value = os.environ["PYTHON_DOTENV_DISABLED"].casefold() - return value in {"1", "true", "t", "yes", "y"} - - -def with_warn_for_invalid_lines(mappings: Iterator[Binding]) -> Iterator[Binding]: - for mapping in mappings: - if mapping.error: - logger.warning( - "python-dotenv could not parse statement starting at line %s", - mapping.original.line, - ) - yield mapping - - -class DotEnv: - def __init__( - self, - dotenv_path: Optional[StrPath], - stream: Optional[IO[str]] = None, - verbose: bool = False, - encoding: Optional[str] = None, - interpolate: bool = True, - override: bool = True, - ) -> None: - self.dotenv_path: Optional[StrPath] = dotenv_path - self.stream: Optional[IO[str]] = stream - self._dict: Optional[Dict[str, Optional[str]]] = None - self.verbose: bool = verbose - self.encoding: Optional[str] = encoding - self.interpolate: bool = interpolate - self.override: bool = override - - @contextmanager - def _get_stream(self) -> Iterator[IO[str]]: - if self.dotenv_path and _is_file_or_fifo(self.dotenv_path): - with open(self.dotenv_path, encoding=self.encoding) as stream: - yield stream - elif self.stream is not None: - yield self.stream - else: - if self.verbose: - logger.info( - "python-dotenv could not find configuration file %s.", - self.dotenv_path or ".env", - ) - yield io.StringIO("") - - def dict(self) -> Dict[str, Optional[str]]: - """Return dotenv as dict""" - if self._dict: - return self._dict - - raw_values = self.parse() - - if self.interpolate: - self._dict = OrderedDict( - resolve_variables(raw_values, override=self.override) - ) - else: - self._dict = OrderedDict(raw_values) - - return self._dict - - def parse(self) -> Iterator[Tuple[str, Optional[str]]]: - with self._get_stream() as stream: - for mapping in with_warn_for_invalid_lines(parse_stream(stream)): - if mapping.key is not None: - yield mapping.key, mapping.value - - def set_as_environment_variables(self) -> bool: - """ - Load the current dotenv as system environment variable. - """ - if not self.dict(): - return False - - for k, v in self.dict().items(): - if k in os.environ and not self.override: - continue - if v is not None: - os.environ[k] = v - - return True - - def get(self, key: str) -> Optional[str]: - """ """ - data = self.dict() - - if key in data: - return data[key] - - if self.verbose: - logger.warning("Key %s not found in %s.", key, self.dotenv_path) - - return None - - -def get_key( - dotenv_path: StrPath, - key_to_get: str, - encoding: Optional[str] = "utf-8", -) -> Optional[str]: - """ - Get the value of a given key from the given .env. - - Returns `None` if the key isn't found or doesn't have a value. - """ - return DotEnv(dotenv_path, verbose=True, encoding=encoding).get(key_to_get) - - -@contextmanager -def rewrite( - path: StrPath, - encoding: Optional[str], - follow_symlinks: bool = False, -) -> Iterator[Tuple[IO[str], IO[str]]]: - if follow_symlinks: - path = os.path.realpath(path) - - try: - source: IO[str] = open(path, encoding=encoding) - try: - path_stat = os.lstat(path) - original_mode: Optional[int] = ( - stat.S_IMODE(path_stat.st_mode) - if stat.S_ISREG(path_stat.st_mode) - else None - ) - except BaseException: - source.close() - raise - except FileNotFoundError: - source = io.StringIO("") - original_mode = None - - with tempfile.NamedTemporaryFile( - mode="w", - encoding=encoding, - delete=False, - prefix=".tmp_", - dir=os.path.dirname(os.path.abspath(path)), - ) as dest: - dest_path = pathlib.Path(dest.name) - error = None - - try: - with source: - yield (source, dest) - except BaseException as err: - error = err - - if error is None: - try: - if original_mode is not None: - os.chmod(dest_path, original_mode) - - os.replace(dest_path, path) - except BaseException: - dest_path.unlink(missing_ok=True) - raise - else: - dest_path.unlink(missing_ok=True) - raise error from None - - -def set_key( - dotenv_path: StrPath, - key_to_set: str, - value_to_set: str, - quote_mode: str = "always", - export: bool = False, - encoding: Optional[str] = "utf-8", - follow_symlinks: bool = False, -) -> Tuple[Optional[bool], str, str]: - """ - Adds or Updates a key/value to the given .env - - The target .env file is created if it doesn't exist. - - This function doesn't follow symlinks by default, to avoid accidentally - modifying a file at a potentially untrusted path. If you don't need this - protection and need symlinks to be followed, use `follow_symlinks`. - """ - if quote_mode not in ("always", "auto", "never"): - raise ValueError(f"Unknown quote_mode: {quote_mode}") - - quote = quote_mode == "always" or ( - quote_mode == "auto" and not value_to_set.isalnum() - ) - - if quote: - value_out = "'{}'".format(value_to_set.replace("'", "\\'")) - else: - value_out = value_to_set - if export: - line_out = f"export {key_to_set}={value_out}\n" - else: - line_out = f"{key_to_set}={value_out}\n" - - with rewrite(dotenv_path, encoding=encoding, follow_symlinks=follow_symlinks) as ( - source, - dest, - ): - replaced = False - missing_newline = False - for mapping in with_warn_for_invalid_lines(parse_stream(source)): - if mapping.key == key_to_set: - dest.write(line_out) - replaced = True - else: - dest.write(mapping.original.string) - missing_newline = not mapping.original.string.endswith("\n") - if not replaced: - if missing_newline: - dest.write("\n") - dest.write(line_out) - - return True, key_to_set, value_to_set - - -def unset_key( - dotenv_path: StrPath, - key_to_unset: str, - quote_mode: str = "always", - encoding: Optional[str] = "utf-8", - follow_symlinks: bool = False, -) -> Tuple[Optional[bool], str]: - """ - Removes a given key from the given `.env` file. - - If the .env path given doesn't exist, fails. - If the given key doesn't exist in the .env, fails. - - This function doesn't follow symlinks by default, to avoid accidentally - modifying a file at a potentially untrusted path. If you don't need this - protection and need symlinks to be followed, use `follow_symlinks`. - """ - if not os.path.exists(dotenv_path): - logger.warning("Can't delete from %s - it doesn't exist.", dotenv_path) - return None, key_to_unset - - removed = False - with rewrite(dotenv_path, encoding=encoding, follow_symlinks=follow_symlinks) as ( - source, - dest, - ): - for mapping in with_warn_for_invalid_lines(parse_stream(source)): - if mapping.key == key_to_unset: - removed = True - else: - dest.write(mapping.original.string) - - if not removed: - logger.warning( - "Key %s not removed from %s - key doesn't exist.", key_to_unset, dotenv_path - ) - return None, key_to_unset - - return removed, key_to_unset - - -def resolve_variables( - values: Iterable[Tuple[str, Optional[str]]], - override: bool, -) -> Mapping[str, Optional[str]]: - new_values: Dict[str, Optional[str]] = {} - - for name, value in values: - if value is None: - result = None - else: - atoms = parse_variables(value) - env: Dict[str, Optional[str]] = {} - if override: - env.update(os.environ) # type: ignore - env.update(new_values) - else: - env.update(new_values) - env.update(os.environ) # type: ignore - result = "".join(atom.resolve(env) for atom in atoms) - - new_values[name] = result - - return new_values - - -def _walk_to_root(path: str) -> Iterator[str]: - """ - Yield directories starting from the given directory up to the root - """ - if not os.path.exists(path): - raise IOError("Starting path not found") - - if os.path.isfile(path): - path = os.path.dirname(path) - - last_dir = None - current_dir = os.path.abspath(path) - while last_dir != current_dir: - yield current_dir - parent_dir = os.path.abspath(os.path.join(current_dir, os.path.pardir)) - last_dir, current_dir = current_dir, parent_dir - - -def find_dotenv( - filename: str = ".env", - raise_error_if_not_found: bool = False, - usecwd: bool = False, -) -> str: - """ - Search in increasingly higher folders for the given file - - Returns path to the file if found, or an empty string otherwise - """ - - def _is_interactive(): - """Decide whether this is running in a REPL or IPython notebook""" - if hasattr(sys, "ps1") or hasattr(sys, "ps2"): - return True - try: - main = __import__("__main__", None, None, fromlist=["__file__"]) - except ModuleNotFoundError: - return False - return not hasattr(main, "__file__") - - def _is_debugger(): - return sys.gettrace() is not None - - if usecwd or _is_interactive() or _is_debugger() or getattr(sys, "frozen", False): - # Should work without __file__, e.g. in REPL or IPython notebook. - path = os.getcwd() - else: - # will work for .py files - frame = sys._getframe() - current_file = __file__ - - while frame.f_code.co_filename == current_file or not os.path.exists( - frame.f_code.co_filename - ): - assert frame.f_back is not None - frame = frame.f_back - frame_filename = frame.f_code.co_filename - path = os.path.dirname(os.path.abspath(frame_filename)) - - for dirname in _walk_to_root(path): - check_path = os.path.join(dirname, filename) - if _is_file_or_fifo(check_path): - return check_path - - if raise_error_if_not_found: - raise IOError("File not found") - - return "" - - -def load_dotenv( - dotenv_path: Optional[StrPath] = None, - stream: Optional[IO[str]] = None, - verbose: bool = False, - override: bool = False, - interpolate: bool = True, - encoding: Optional[str] = "utf-8", -) -> bool: - """Parse a .env file and then load all the variables found as environment variables. - - Parameters: - dotenv_path: Absolute or relative path to .env file. - stream: Text stream (such as `io.StringIO`) with .env content, used if - `dotenv_path` is `None`. - verbose: Whether to output a warning the .env file is missing. - override: Whether to override the system environment variables with the variables - from the `.env` file. - encoding: Encoding to be used to read the file. - Returns: - Bool: True if at least one environment variable is set else False - - If both `dotenv_path` and `stream` are `None`, `find_dotenv()` is used to find the - .env file with it's default parameters. If you need to change the default parameters - of `find_dotenv()`, you can explicitly call `find_dotenv()` and pass the result - to this function as `dotenv_path`. - - If the environment variable `PYTHON_DOTENV_DISABLED` is set to a truthy value, - .env loading is disabled. - """ - if _load_dotenv_disabled(): - logger.debug( - "python-dotenv: .env loading disabled by PYTHON_DOTENV_DISABLED environment variable" - ) - return False - - if dotenv_path is None and stream is None: - dotenv_path = find_dotenv() - - dotenv = DotEnv( - dotenv_path=dotenv_path, - stream=stream, - verbose=verbose, - interpolate=interpolate, - override=override, - encoding=encoding, - ) - return dotenv.set_as_environment_variables() - - -def dotenv_values( - dotenv_path: Optional[StrPath] = None, - stream: Optional[IO[str]] = None, - verbose: bool = False, - interpolate: bool = True, - encoding: Optional[str] = "utf-8", -) -> Dict[str, Optional[str]]: - """ - Parse a .env file and return its content as a dict. - - The returned dict will have `None` values for keys without values in the .env file. - For example, `foo=bar` results in `{"foo": "bar"}` whereas `foo` alone results in - `{"foo": None}` - - Parameters: - dotenv_path: Absolute or relative path to the .env file. - stream: `StringIO` object with .env content, used if `dotenv_path` is `None`. - verbose: Whether to output a warning if the .env file is missing. - encoding: Encoding to be used to read the file. - - If both `dotenv_path` and `stream` are `None`, `find_dotenv()` is used to find the - .env file. - """ - if dotenv_path is None and stream is None: - dotenv_path = find_dotenv() - - return DotEnv( - dotenv_path=dotenv_path, - stream=stream, - verbose=verbose, - interpolate=interpolate, - override=True, - encoding=encoding, - ).dict() - - -def _is_file_or_fifo(path: StrPath) -> bool: - """ - Return True if `path` exists and is either a regular file or a FIFO. - """ - if os.path.isfile(path): - return True - - try: - st = os.stat(path) - except (FileNotFoundError, OSError): - return False - - return stat.S_ISFIFO(st.st_mode) diff --git a/server/venv/Lib/site-packages/dotenv/parser.py b/server/venv/Lib/site-packages/dotenv/parser.py deleted file mode 100644 index eb100b4..0000000 --- a/server/venv/Lib/site-packages/dotenv/parser.py +++ /dev/null @@ -1,182 +0,0 @@ -import codecs -import re -from typing import ( - IO, - Iterator, - Match, - NamedTuple, - Optional, - Pattern, - Sequence, -) - - -def make_regex(string: str, extra_flags: int = 0) -> Pattern[str]: - return re.compile(string, re.UNICODE | extra_flags) - - -_newline = make_regex(r"(\r\n|\n|\r)") -_multiline_whitespace = make_regex(r"\s*", extra_flags=re.MULTILINE) -_whitespace = make_regex(r"[^\S\r\n]*") -_export = make_regex(r"(?:export[^\S\r\n]+)?") -_single_quoted_key = make_regex(r"'([^']+)'") -_unquoted_key = make_regex(r"([^=\#\s]+)") -_equal_sign = make_regex(r"(=[^\S\r\n]*)") -_single_quoted_value = make_regex(r"'((?:\\'|[^'])*)'") -_double_quoted_value = make_regex(r'"((?:\\"|[^"])*)"') -_unquoted_value = make_regex(r"([^\r\n]*)") -_comment = make_regex(r"(?:[^\S\r\n]*#[^\r\n]*)?") -_end_of_line = make_regex(r"[^\S\r\n]*(?:\r\n|\n|\r|$)") -_rest_of_line = make_regex(r"[^\r\n]*(?:\r|\n|\r\n)?") -_double_quote_escapes = make_regex(r"\\[\\'\"abfnrtv]") -_single_quote_escapes = make_regex(r"\\[\\']") - - -class Original(NamedTuple): - string: str - line: int - - -class Binding(NamedTuple): - key: Optional[str] - value: Optional[str] - original: Original - error: bool - - -class Position: - def __init__(self, chars: int, line: int) -> None: - self.chars = chars - self.line = line - - @classmethod - def start(cls) -> "Position": - return cls(chars=0, line=1) - - def set(self, other: "Position") -> None: - self.chars = other.chars - self.line = other.line - - def advance(self, string: str) -> None: - self.chars += len(string) - self.line += len(re.findall(_newline, string)) - - -class Error(Exception): - pass - - -class Reader: - def __init__(self, stream: IO[str]) -> None: - self.string = stream.read() - self.position = Position.start() - self.mark = Position.start() - - def has_next(self) -> bool: - return self.position.chars < len(self.string) - - def set_mark(self) -> None: - self.mark.set(self.position) - - def get_marked(self) -> Original: - return Original( - string=self.string[self.mark.chars : self.position.chars], - line=self.mark.line, - ) - - def peek(self, count: int) -> str: - return self.string[self.position.chars : self.position.chars + count] - - def read(self, count: int) -> str: - result = self.string[self.position.chars : self.position.chars + count] - if len(result) < count: - raise Error("read: End of string") - self.position.advance(result) - return result - - def read_regex(self, regex: Pattern[str]) -> Sequence[str]: - match = regex.match(self.string, self.position.chars) - if match is None: - raise Error("read_regex: Pattern not found") - self.position.advance(self.string[match.start() : match.end()]) - return match.groups() - - -def decode_escapes(regex: Pattern[str], string: str) -> str: - def decode_match(match: Match[str]) -> str: - return codecs.decode(match.group(0), "unicode-escape") # type: ignore - - return regex.sub(decode_match, string) - - -def parse_key(reader: Reader) -> Optional[str]: - char = reader.peek(1) - if char == "#": - return None - elif char == "'": - (key,) = reader.read_regex(_single_quoted_key) - else: - (key,) = reader.read_regex(_unquoted_key) - return key - - -def parse_unquoted_value(reader: Reader) -> str: - (part,) = reader.read_regex(_unquoted_value) - return re.sub(r"\s+#.*", "", part).rstrip() - - -def parse_value(reader: Reader) -> str: - char = reader.peek(1) - if char == "'": - (value,) = reader.read_regex(_single_quoted_value) - return decode_escapes(_single_quote_escapes, value) - elif char == '"': - (value,) = reader.read_regex(_double_quoted_value) - return decode_escapes(_double_quote_escapes, value) - elif char in ("", "\n", "\r"): - return "" - else: - return parse_unquoted_value(reader) - - -def parse_binding(reader: Reader) -> Binding: - reader.set_mark() - try: - reader.read_regex(_multiline_whitespace) - if not reader.has_next(): - return Binding( - key=None, - value=None, - original=reader.get_marked(), - error=False, - ) - reader.read_regex(_export) - key = parse_key(reader) - reader.read_regex(_whitespace) - if reader.peek(1) == "=": - reader.read_regex(_equal_sign) - value: Optional[str] = parse_value(reader) - else: - value = None - reader.read_regex(_comment) - reader.read_regex(_end_of_line) - return Binding( - key=key, - value=value, - original=reader.get_marked(), - error=False, - ) - except Error: - reader.read_regex(_rest_of_line) - return Binding( - key=None, - value=None, - original=reader.get_marked(), - error=True, - ) - - -def parse_stream(stream: IO[str]) -> Iterator[Binding]: - reader = Reader(stream) - while reader.has_next(): - yield parse_binding(reader) diff --git a/server/venv/Lib/site-packages/dotenv/py.typed b/server/venv/Lib/site-packages/dotenv/py.typed deleted file mode 100644 index 7632ecf..0000000 --- a/server/venv/Lib/site-packages/dotenv/py.typed +++ /dev/null @@ -1 +0,0 @@ -# Marker file for PEP 561 diff --git a/server/venv/Lib/site-packages/dotenv/variables.py b/server/venv/Lib/site-packages/dotenv/variables.py deleted file mode 100644 index 667f2f2..0000000 --- a/server/venv/Lib/site-packages/dotenv/variables.py +++ /dev/null @@ -1,86 +0,0 @@ -import re -from abc import ABCMeta, abstractmethod -from typing import Iterator, Mapping, Optional, Pattern - -_posix_variable: Pattern[str] = re.compile( - r""" - \$\{ - (?P[^\}:]*) - (?::- - (?P[^\}]*) - )? - \} - """, - re.VERBOSE, -) - - -class Atom(metaclass=ABCMeta): - def __ne__(self, other: object) -> bool: - result = self.__eq__(other) - if result is NotImplemented: - return NotImplemented - return not result - - @abstractmethod - def resolve(self, env: Mapping[str, Optional[str]]) -> str: ... - - -class Literal(Atom): - def __init__(self, value: str) -> None: - self.value = value - - def __repr__(self) -> str: - return f"Literal(value={self.value})" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, self.__class__): - return NotImplemented - return self.value == other.value - - def __hash__(self) -> int: - return hash((self.__class__, self.value)) - - def resolve(self, env: Mapping[str, Optional[str]]) -> str: - return self.value - - -class Variable(Atom): - def __init__(self, name: str, default: Optional[str]) -> None: - self.name = name - self.default = default - - def __repr__(self) -> str: - return f"Variable(name={self.name}, default={self.default})" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, self.__class__): - return NotImplemented - return (self.name, self.default) == (other.name, other.default) - - def __hash__(self) -> int: - return hash((self.__class__, self.name, self.default)) - - def resolve(self, env: Mapping[str, Optional[str]]) -> str: - default = self.default if self.default is not None else "" - result = env.get(self.name, default) - return result if result is not None else "" - - -def parse_variables(value: str) -> Iterator[Atom]: - cursor = 0 - - for match in _posix_variable.finditer(value): - (start, end) = match.span() - name = match["name"] - default = match["default"] - - if start > cursor: - yield Literal(value=value[cursor:start]) - - yield Variable(name=name, default=default) - cursor = end - - length = len(value) - if cursor < length: - yield Literal(value=value[cursor:length]) diff --git a/server/venv/Lib/site-packages/dotenv/version.py b/server/venv/Lib/site-packages/dotenv/version.py deleted file mode 100644 index bc86c94..0000000 --- a/server/venv/Lib/site-packages/dotenv/version.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "1.2.2" diff --git a/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/INSTALLER b/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/METADATA b/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/METADATA deleted file mode 100644 index bf3259f..0000000 --- a/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/METADATA +++ /dev/null @@ -1,616 +0,0 @@ -Metadata-Version: 2.4 -Name: fastapi -Version: 0.138.0 -Summary: FastAPI framework, high performance, easy to learn, fast to code, ready for production -Author-Email: =?utf-8?q?Sebasti=C3=A1n_Ram=C3=ADrez?= -License-Expression: MIT -License-File: LICENSE -Classifier: Intended Audience :: Information Technology -Classifier: Intended Audience :: System Administrators -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python -Classifier: Topic :: Internet -Classifier: Topic :: Software Development :: Libraries :: Application Frameworks -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Software Development :: Libraries -Classifier: Topic :: Software Development -Classifier: Typing :: Typed -Classifier: Development Status :: 4 - Beta -Classifier: Environment :: Web Environment -Classifier: Framework :: AsyncIO -Classifier: Framework :: FastAPI -Classifier: Framework :: Pydantic -Classifier: Framework :: Pydantic :: 2 -Classifier: Intended Audience :: Developers -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers -Classifier: Topic :: Internet :: WWW/HTTP -Project-URL: Homepage, https://github.com/fastapi/fastapi -Project-URL: Documentation, https://fastapi.tiangolo.com/ -Project-URL: Repository, https://github.com/fastapi/fastapi -Project-URL: Issues, https://github.com/fastapi/fastapi/issues -Project-URL: Changelog, https://fastapi.tiangolo.com/release-notes/ -Requires-Python: >=3.10 -Requires-Dist: starlette>=0.46.0 -Requires-Dist: pydantic>=2.9.0 -Requires-Dist: typing-extensions>=4.8.0 -Requires-Dist: typing-inspection>=0.4.2 -Requires-Dist: annotated-doc>=0.0.2 -Provides-Extra: standard -Requires-Dist: fastapi-cli[standard]>=0.0.8; extra == "standard" -Requires-Dist: fastar>=0.9.0; extra == "standard" -Requires-Dist: httpx<1.0.0,>=0.23.0; extra == "standard" -Requires-Dist: jinja2>=3.1.5; extra == "standard" -Requires-Dist: python-multipart>=0.0.18; extra == "standard" -Requires-Dist: email-validator>=2.0.0; extra == "standard" -Requires-Dist: uvicorn[standard]>=0.12.0; extra == "standard" -Requires-Dist: pydantic-settings>=2.0.0; extra == "standard" -Requires-Dist: pydantic-extra-types>=2.0.0; extra == "standard" -Provides-Extra: standard-no-fastapi-cloud-cli -Requires-Dist: fastapi-cli[standard-no-fastapi-cloud-cli]>=0.0.8; extra == "standard-no-fastapi-cloud-cli" -Requires-Dist: httpx<1.0.0,>=0.23.0; extra == "standard-no-fastapi-cloud-cli" -Requires-Dist: jinja2>=3.1.5; extra == "standard-no-fastapi-cloud-cli" -Requires-Dist: python-multipart>=0.0.18; extra == "standard-no-fastapi-cloud-cli" -Requires-Dist: email-validator>=2.0.0; extra == "standard-no-fastapi-cloud-cli" -Requires-Dist: uvicorn[standard]>=0.12.0; extra == "standard-no-fastapi-cloud-cli" -Requires-Dist: pydantic-settings>=2.0.0; extra == "standard-no-fastapi-cloud-cli" -Requires-Dist: pydantic-extra-types>=2.0.0; extra == "standard-no-fastapi-cloud-cli" -Provides-Extra: all -Requires-Dist: fastapi-cli[standard]>=0.0.8; extra == "all" -Requires-Dist: httpx<1.0.0,>=0.23.0; extra == "all" -Requires-Dist: jinja2>=3.1.5; extra == "all" -Requires-Dist: python-multipart>=0.0.18; extra == "all" -Requires-Dist: itsdangerous>=1.1.0; extra == "all" -Requires-Dist: pyyaml>=5.3.1; extra == "all" -Requires-Dist: email-validator>=2.0.0; extra == "all" -Requires-Dist: uvicorn[standard]>=0.12.0; extra == "all" -Requires-Dist: pydantic-settings>=2.0.0; extra == "all" -Requires-Dist: pydantic-extra-types>=2.0.0; extra == "all" -Description-Content-Type: text/markdown - -

- FastAPI -

-

- FastAPI framework, high performance, easy to learn, fast to code, ready for production -

-

- - Test - - - Coverage - - - Package version - - - Supported Python versions - -

- ---- - -**Documentation**: [https://fastapi.tiangolo.com](https://fastapi.tiangolo.com) - -**Source Code**: [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi) - ---- - -FastAPI is a modern, fast (high-performance), web framework for building APIs with Python based on standard Python type hints. - -The key features are: - -* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance). -* **Fast to code**: Increase the speed to develop features by about 200% to 300%. * -* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. * -* **Intuitive**: Great editor support. Completion everywhere. Less time debugging. -* **Easy**: Designed to be easy to use and learn. Less time reading docs. -* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs. -* **Robust**: Get production-ready code. With automatic interactive documentation. -* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: [OpenAPI](https://github.com/OAI/OpenAPI-Specification) (previously known as Swagger) and [JSON Schema](https://json-schema.org/). - -* estimation based on tests conducted by an internal development team, building production applications. - -## Sponsors - - -### Keystone Sponsor - - - -### Gold Sponsors - - - - - - - - - - -### Silver Sponsors - - - - - - - - - - - -[Other sponsors](https://fastapi.tiangolo.com/fastapi-people/#sponsors) - -## Opinions - - - -
- -"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" - -
Kabir Khan - Microsoft (ref)
- ---- - -"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_" - -
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
- ---- - -"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_" - -
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
- ---- - -"_If anyone is looking to build a production Python API, I would highly recommend **FastAPI**. It is **beautifully designed**, **simple to use** and **highly scalable**, it has become a **key component** in our API first development strategy and is driving many automations and services such as our Virtual TAC Engineer._" - -
Deon Pillsbury - Cisco (ref)
- ---- - -
- -## FastAPI Conf - -[**FastAPI Conf '26**](https://fastapiconf.com) is happening on **October 28, 2026** in **Amsterdam, NL**. All about FastAPI, right from the source. 🎤 - -FastAPI Conf '26 - October 28, 2026 - Amsterdam, NL - -## FastAPI mini documentary - -There's a [FastAPI mini documentary](https://www.youtube.com/watch?v=mpR8ngthqiE) released at the end of 2025, you can watch it online: - -FastAPI Mini Documentary - -## **Typer**, the FastAPI of CLIs - - - -If you are building a CLI app to be used in the terminal instead of a web API, check out [**Typer**](https://typer.tiangolo.com/). - -**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀 - -## Requirements - -FastAPI stands on the shoulders of giants: - -* [Starlette](https://www.starlette.dev/) for the web parts. -* [Pydantic](https://docs.pydantic.dev/) for the data parts. - -## Installation - -Create and activate a [virtual environment](https://fastapi.tiangolo.com/virtual-environments/) and then install FastAPI: - -
- -```console -$ pip install "fastapi[standard]" - ----> 100% -``` - -
- -**Note**: Make sure you put `"fastapi[standard]"` in quotes to ensure it works in all terminals. - -## Example - -### Create it - -Create a file `main.py` with: - -```Python -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int, q: str | None = None): - return {"item_id": item_id, "q": q} -``` - -
-Or use async def... - -If your code uses `async` / `await`, use `async def`: - -```Python hl_lines="7 12" -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -async def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -async def read_item(item_id: int, q: str | None = None): - return {"item_id": item_id, "q": q} -``` - -**Note**: - -If you don't know, check the _"In a hurry?"_ section about [`async` and `await` in the docs](https://fastapi.tiangolo.com/async/#in-a-hurry). - -
- -### Run it - -Run the server with: - -
- -```console -$ fastapi dev - - ╭────────── FastAPI CLI - Development mode ───────────╮ - │ │ - │ Serving at: http://127.0.0.1:8000 │ - │ │ - │ API docs: http://127.0.0.1:8000/docs │ - │ │ - │ Running in development mode, for production use: │ - │ │ - │ fastapi run │ - │ │ - ╰─────────────────────────────────────────────────────╯ - -INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp'] -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [2248755] using WatchFiles -INFO: Started server process [2248757] -INFO: Waiting for application startup. -INFO: Application startup complete. -``` - -
- -
-About the command fastapi dev... - -The command `fastapi dev` reads your `main.py` file automatically, detects the **FastAPI** app in it, and starts a server using [Uvicorn](https://www.uvicorn.dev). - -By default, `fastapi dev` will start with auto-reload enabled for local development. - -You can read more about it in the [FastAPI CLI docs](https://fastapi.tiangolo.com/fastapi-cli/). - -
- -### Check it - -Open your browser at [http://127.0.0.1:8000/items/5?q=somequery](http://127.0.0.1:8000/items/5?q=somequery). - -You will see the JSON response as: - -```JSON -{"item_id": 5, "q": "somequery"} -``` - -You already created an API that: - -* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`. -* Both _paths_ take `GET` operations (also known as HTTP _methods_). -* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`. -* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`. - -### Interactive API docs - -Now go to [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs). - -You will see the automatic interactive API documentation (provided by [Swagger UI](https://github.com/swagger-api/swagger-ui)): - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) - -### Alternative API docs - -And now, go to [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc). - -You will see the alternative automatic documentation (provided by [ReDoc](https://github.com/Rebilly/ReDoc)): - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) - -## Example upgrade - -Now modify the file `main.py` to receive a body from a `PUT` request. - -Declare the body using standard Python types, thanks to Pydantic. - -```Python hl_lines="2 7-10 23-25" -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - price: float - is_offer: bool | None = None - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int, q: str | None = None): - return {"item_id": item_id, "q": q} - - -@app.put("/items/{item_id}") -def update_item(item_id: int, item: Item): - return {"item_name": item.name, "item_id": item_id} -``` - -The `fastapi dev` server should reload automatically. - -### Interactive API docs upgrade - -Now go to [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs). - -* The interactive API documentation will be automatically updated, including the new body: - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) - -* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) - -* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) - -### Alternative API docs upgrade - -And now, go to [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc). - -* The alternative documentation will also reflect the new query parameter and body: - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) - -### Recap - -In summary, you declare **once** the types of parameters, body, etc. as function parameters. - -You do that with standard modern Python types. - -You don't have to learn a new syntax, the methods or classes of a specific library, etc. - -Just standard **Python**. - -For example, for an `int`: - -```Python -item_id: int -``` - -or for a more complex `Item` model: - -```Python -item: Item -``` - -...and with that single declaration you get: - -* Editor support, including: - * Completion. - * Type checks. -* Validation of data: - * Automatic and clear errors when the data is invalid. - * Validation even for deeply nested JSON objects. -* Conversion of input data: coming from the network to Python data and types. Reading from: - * JSON. - * Path parameters. - * Query parameters. - * Cookies. - * Headers. - * Forms. - * Files. -* Conversion of output data: converting from Python data and types to network data (as JSON): - * Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc). - * `datetime` objects. - * `UUID` objects. - * Database models. - * ...and many more. -* Automatic interactive API documentation, including 2 alternative user interfaces: - * Swagger UI. - * ReDoc. - ---- - -Coming back to the previous code example, **FastAPI** will: - -* Validate that there is an `item_id` in the path for `GET` and `PUT` requests. -* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests. - * If it is not, the client will see a useful, clear error. -* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests. - * As the `q` parameter is declared with `= None`, it is optional. - * Without the `None` it would be required (as is the body in the case with `PUT`). -* For `PUT` requests to `/items/{item_id}`, read the body as JSON: - * Check that it has a required attribute `name` that should be a `str`. - * Check that it has a required attribute `price` that has to be a `float`. - * Check that it has an optional attribute `is_offer`, that should be a `bool`, if present. - * All this would also work for deeply nested JSON objects. -* Convert from and to JSON automatically. -* Document everything with OpenAPI, that can be used by: - * Interactive documentation systems. - * Automatic client code generation systems, for many languages. -* Provide 2 interactive documentation web interfaces directly. - ---- - -We just scratched the surface, but you already get the idea of how it all works. - -Try changing the line with: - -```Python - return {"item_name": item.name, "item_id": item_id} -``` - -...from: - -```Python - ... "item_name": item.name ... -``` - -...to: - -```Python - ... "item_price": item.price ... -``` - -...and see how your editor will auto-complete the attributes and know their types: - -![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) - -For a more complete example including more features, see the Tutorial - User Guide. - -**Spoiler alert**: the tutorial - user guide includes: - -* Declaration of **parameters** from other different places such as: **headers**, **cookies**, **form fields** and **files**. -* How to set **validation constraints** such as `maximum_length` or `regex`. -* A very powerful and easy to use **Dependency Injection** system. -* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth. -* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic). -* **GraphQL** integration with [Strawberry](https://strawberry.rocks) and other libraries. -* Many extra features (thanks to Starlette) such as: - * **WebSockets** - * extremely easy tests based on HTTPX and `pytest` - * **CORS** - * **Cookie Sessions** - * ...and more. - -### Deploy your app (optional) - -You can optionally deploy your FastAPI app to [FastAPI Cloud](https://fastapicloud.com) with a single command. 🚀 - -
- -```console -$ fastapi deploy - -Deploying to FastAPI Cloud... - -✅ Deployment successful! - -🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev -``` - -
- -The CLI will automatically detect your FastAPI application and deploy it to the cloud. If you are not logged in, your browser will open to complete the authentication process. - -That's it! Now you can access your app at that URL. ✨ - -#### About FastAPI Cloud - -**[FastAPI Cloud](https://fastapicloud.com)** is built by the same author and team behind **FastAPI**. - -It streamlines the process of **building**, **deploying**, and **accessing** an API with minimal effort. - -It brings the same **developer experience** of building apps with FastAPI to **deploying** them to the cloud. 🎉 - -FastAPI Cloud is the primary sponsor and funding provider for the *FastAPI and friends* open source projects. ✨ - -#### Deploy to other cloud providers - -FastAPI is open source and based on standards. You can deploy FastAPI apps to any cloud provider you choose. - -Follow your cloud provider's guides to deploy FastAPI apps with them. 🤓 - -## Performance - -Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as [one of the fastest Python frameworks available](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7), only below Starlette and Uvicorn themselves (used internally by FastAPI). (*) - -To understand more about it, see the section [Benchmarks](https://fastapi.tiangolo.com/benchmarks/). - -## Dependencies - -FastAPI depends on Pydantic and Starlette. - -### `standard` Dependencies - -When you install FastAPI with `pip install "fastapi[standard]"` it comes with the `standard` group of optional dependencies: - -Used by Pydantic: - -* [`email-validator`](https://github.com/JoshData/python-email-validator) - for email validation. - -Used by Starlette: - -* [`httpx`](https://www.python-httpx.org) - Required if you want to use the `TestClient`. -* [`jinja2`](https://jinja.palletsprojects.com) - Required if you want to use the default template configuration. -* [`python-multipart`](https://github.com/Kludex/python-multipart) - Required if you want to support form "parsing", with `request.form()`. - -Used by FastAPI: - -* [`uvicorn`](https://www.uvicorn.dev) - for the server that loads and serves your application. This includes `uvicorn[standard]`, which includes some dependencies (e.g. `uvloop`) needed for high performance serving. -* `fastapi-cli[standard]` - to provide the `fastapi` command. - * This includes `fastapi-cloud-cli`, which allows you to deploy your FastAPI application to [FastAPI Cloud](https://fastapicloud.com). - -### Without `standard` Dependencies - -If you don't want to include the `standard` optional dependencies, you can install with `pip install fastapi` instead of `pip install "fastapi[standard]"`. - -### Without `fastapi-cloud-cli` - -If you want to install FastAPI with the standard dependencies but without the `fastapi-cloud-cli`, you can install with `pip install "fastapi[standard-no-fastapi-cloud-cli]"`. - -### Additional Optional Dependencies - -There are some additional dependencies you might want to install. - -Additional optional Pydantic dependencies: - -* [`pydantic-settings`](https://docs.pydantic.dev/latest/usage/pydantic_settings/) - for settings management. -* [`pydantic-extra-types`](https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/) - for extra types to be used with Pydantic. - -Additional optional FastAPI dependencies: - -* [`orjson`](https://github.com/ijl/orjson) - Required if you want to use `ORJSONResponse`. -* [`ujson`](https://github.com/esnme/ultrajson) - Required if you want to use `UJSONResponse`. - -## License - -This project is licensed under the terms of the MIT license. diff --git a/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/RECORD b/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/RECORD deleted file mode 100644 index ef7e49e..0000000 --- a/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/RECORD +++ /dev/null @@ -1,109 +0,0 @@ -../../Scripts/fastapi.exe,sha256=5j15NkpabsAZ8L1Pep_hF7JB3hy_Dy0jiCVi5MDNunU,108459 -fastapi-0.138.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -fastapi-0.138.0.dist-info/METADATA,sha256=Ljq5wAm9GugY3jIBZNrFULS04Z8bKjJr1a9G5OVUPtY,27208 -fastapi-0.138.0.dist-info/RECORD,, -fastapi-0.138.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -fastapi-0.138.0.dist-info/WHEEL,sha256=VP-D4TPS230sME9Z3vb3INXvo1yt0924YRm5AOsk_dE,90 -fastapi-0.138.0.dist-info/entry_points.txt,sha256=GCf-WbIZxyGT4MUmrPGj1cOHYZoGsNPHAvNkT6hnGeA,61 -fastapi-0.138.0.dist-info/licenses/LICENSE,sha256=Tsif_IFIW5f-xYSy1KlhAy7v_oNEU4lP2cEnSQbMdE4,1086 -fastapi/.agents/skills/fastapi/SKILL.md,sha256=sJ7wiSY8WOd9YhhMd9nd2iGJWtIjox_JpaYxHV1HB1M,11240 -fastapi/.agents/skills/fastapi/references/dependencies.md,sha256=i2txoD-hRoCQWoH1PxiDuQwqt6xl7vp3wmZMLQON5Gk,3268 -fastapi/.agents/skills/fastapi/references/other-tools.md,sha256=oskZlYkCdGgezS9mIfqW5kImCGtOsgPUa46Sd81H-P0,1527 -fastapi/.agents/skills/fastapi/references/streaming.md,sha256=bHaIKnwbTkd7TUVQm_uxapUnAlEG4rdvALV9koD5ypI,2581 -fastapi/__init__.py,sha256=Q2cJRNvOpEZdE7ZHIgqtAS1bEvOw6pDaE8d3lC3EGXs,1081 -fastapi/__main__.py,sha256=bKePXLdO4SsVSM6r9SVoLickJDcR2c0cTOxZRKq26YQ,37 -fastapi/__pycache__/__init__.cpython-313.pyc,, -fastapi/__pycache__/__main__.cpython-313.pyc,, -fastapi/__pycache__/applications.cpython-313.pyc,, -fastapi/__pycache__/background.cpython-313.pyc,, -fastapi/__pycache__/cli.cpython-313.pyc,, -fastapi/__pycache__/concurrency.cpython-313.pyc,, -fastapi/__pycache__/datastructures.cpython-313.pyc,, -fastapi/__pycache__/encoders.cpython-313.pyc,, -fastapi/__pycache__/exception_handlers.cpython-313.pyc,, -fastapi/__pycache__/exceptions.cpython-313.pyc,, -fastapi/__pycache__/logger.cpython-313.pyc,, -fastapi/__pycache__/param_functions.cpython-313.pyc,, -fastapi/__pycache__/params.cpython-313.pyc,, -fastapi/__pycache__/requests.cpython-313.pyc,, -fastapi/__pycache__/responses.cpython-313.pyc,, -fastapi/__pycache__/routing.cpython-313.pyc,, -fastapi/__pycache__/sse.cpython-313.pyc,, -fastapi/__pycache__/staticfiles.cpython-313.pyc,, -fastapi/__pycache__/templating.cpython-313.pyc,, -fastapi/__pycache__/testclient.cpython-313.pyc,, -fastapi/__pycache__/types.cpython-313.pyc,, -fastapi/__pycache__/utils.cpython-313.pyc,, -fastapi/__pycache__/websockets.cpython-313.pyc,, -fastapi/_compat/__init__.py,sha256=PYOR-8vJ5va4Qjl810FcQmJbqmpyyeQMoZ9R86CeE2U,2095 -fastapi/_compat/__pycache__/__init__.cpython-313.pyc,, -fastapi/_compat/__pycache__/shared.cpython-313.pyc,, -fastapi/_compat/__pycache__/v2.cpython-313.pyc,, -fastapi/_compat/shared.py,sha256=XJl8cVYOTSgfK-1fiJHLeHHeSGLfC00H7MrtpyYpQgU,7118 -fastapi/_compat/v2.py,sha256=sDGyi1iKSFW9LuJ7n4B61-1yrQI1NHRSwsFRRLuFJ8k,17601 -fastapi/applications.py,sha256=hf4vGBWMU5nEkHmeqQutYBIK3AsnhEwcVF2wIvegekc,183452 -fastapi/background.py,sha256=TADzAethOAaqpVvckYuTT3c4O9N1HaFQysFCPt0MsgU,1820 -fastapi/cli.py,sha256=OYhZb0NR_deuT5ofyPF2NoNBzZDNOP8Salef2nk-HqA,418 -fastapi/concurrency.py,sha256=xHGDEOQAA6cvFEDX46oq3r2t1Zd4sVvreaRgdIE4juM,1489 -fastapi/datastructures.py,sha256=XPugnojHc4N07eF5Xp1TTndP2gMv1fG4k-0L4Vdr7Kc,5321 -fastapi/dependencies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -fastapi/dependencies/__pycache__/__init__.cpython-313.pyc,, -fastapi/dependencies/__pycache__/models.cpython-313.pyc,, -fastapi/dependencies/__pycache__/utils.cpython-313.pyc,, -fastapi/dependencies/models.py,sha256=XPIkEaukHaTaFz9LoeI9f_T-3otOAVkoOC113TpFbWI,7250 -fastapi/dependencies/utils.py,sha256=XIpRML7ttx5EhmchgWz6R5CMsBuepx7KHdmi38F_e_s,39728 -fastapi/encoders.py,sha256=m2OGnq9k94Alcd6UQM8r7iwn-cjvJdpOKRVJuQR68T8,11603 -fastapi/exception_handlers.py,sha256=YVcT8Zy021VYYeecgdyh5YEUjEIHKcLspbkSf4OfbJI,1275 -fastapi/exceptions.py,sha256=fUNOBRdIsULU0TnO8aNBg3HoJeyJxXp9UV6D8wYu9lI,7453 -fastapi/logger.py,sha256=I9NNi3ov8AcqbsbC9wl1X-hdItKgYt2XTrx1f99Zpl4,54 -fastapi/middleware/__init__.py,sha256=oQDxiFVcc1fYJUOIFvphnK7pTT5kktmfL32QXpBFvvo,58 -fastapi/middleware/__pycache__/__init__.cpython-313.pyc,, -fastapi/middleware/__pycache__/asyncexitstack.cpython-313.pyc,, -fastapi/middleware/__pycache__/cors.cpython-313.pyc,, -fastapi/middleware/__pycache__/gzip.cpython-313.pyc,, -fastapi/middleware/__pycache__/httpsredirect.cpython-313.pyc,, -fastapi/middleware/__pycache__/trustedhost.cpython-313.pyc,, -fastapi/middleware/__pycache__/wsgi.cpython-313.pyc,, -fastapi/middleware/asyncexitstack.py,sha256=RKGlQpGzg3GLosqVhrxBy_NCZ9qJS7zQeNHt5Y3x-00,637 -fastapi/middleware/cors.py,sha256=ynwjWQZoc_vbhzZ3_ZXceoaSrslHFHPdoM52rXr0WUU,79 -fastapi/middleware/gzip.py,sha256=xM5PcsH8QlAimZw4VDvcmTnqQamslThsfe3CVN2voa0,79 -fastapi/middleware/httpsredirect.py,sha256=rL8eXMnmLijwVkH7_400zHri1AekfeBd6D6qs8ix950,115 -fastapi/middleware/trustedhost.py,sha256=eE5XGRxGa7c5zPnMJDGp3BxaL25k5iVQlhnv-Pk0Pss,109 -fastapi/middleware/wsgi.py,sha256=a_FMDoeTwcdig9wdAGumIH82oDFfuj4pxtQxLbAw2Ns,107 -fastapi/openapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -fastapi/openapi/__pycache__/__init__.cpython-313.pyc,, -fastapi/openapi/__pycache__/constants.cpython-313.pyc,, -fastapi/openapi/__pycache__/docs.cpython-313.pyc,, -fastapi/openapi/__pycache__/models.cpython-313.pyc,, -fastapi/openapi/__pycache__/utils.cpython-313.pyc,, -fastapi/openapi/constants.py,sha256=adGzmis1L1HJRTE3kJ5fmHS_Noq6tIY6pWv_SFzoFDU,153 -fastapi/openapi/docs.py,sha256=PcjH0Sn-yp97O0exXincG8epsY7ATyJC5662bK1DRao,12425 -fastapi/openapi/models.py,sha256=twjJWGf6lcKRJZgaZCcnQ0Ten1hDhcyCLgbr7tXIP30,14608 -fastapi/openapi/utils.py,sha256=-Haf16aXydAE-IVwloo5_MVBp0l0fi_F9er5wKeKbZ8,26916 -fastapi/param_functions.py,sha256=4fTCVlvEDbAQr7gvWYkOX8hktdl2Iwk-kv4FaTz7P8w,69596 -fastapi/params.py,sha256=1fNNSK5J7PM5Fw-F5_9uOysA2NgC-61mb3LlrBWpqJM,26205 -fastapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -fastapi/requests.py,sha256=zayepKFcienBllv3snmWI20Gk0oHNVLU4DDhqXBb4LU,142 -fastapi/responses.py,sha256=BM7JtiZ_G4j2Z7QvHUzV1KtZPnjOoCfX35RqYXlZDh0,4144 -fastapi/routing.py,sha256=OgQMs5UPY3b1wG8P1BcVa1MrX_ZzUcWV4tEbd12nAKY,246593 -fastapi/security/__init__.py,sha256=bO8pNmxqVRXUjfl2mOKiVZLn0FpBQ61VUYVjmppnbJw,881 -fastapi/security/__pycache__/__init__.cpython-313.pyc,, -fastapi/security/__pycache__/api_key.cpython-313.pyc,, -fastapi/security/__pycache__/base.cpython-313.pyc,, -fastapi/security/__pycache__/http.cpython-313.pyc,, -fastapi/security/__pycache__/oauth2.cpython-313.pyc,, -fastapi/security/__pycache__/open_id_connect_url.cpython-313.pyc,, -fastapi/security/__pycache__/utils.cpython-313.pyc,, -fastapi/security/api_key.py,sha256=4CNLNVAStOsMhytH9C5EOUEOZrtLg_IpMQS_HcRDP4M,9793 -fastapi/security/base.py,sha256=dl4pvbC-RxjfbWgPtCWd8MVU-7CB2SZ22rJDXVCXO6c,141 -fastapi/security/http.py,sha256=Z0xALDqwgJZRAaDs40Sa68rAnjFzEL99UEmO5PJzTKA,13410 -fastapi/security/oauth2.py,sha256=sSqW4tbvoHaWNld46TYatta5rgFfjod4LhxmedXzkI8,24178 -fastapi/security/open_id_connect_url.py,sha256=V8WLPEsEq_WJlIjPwJO2vCoJWGLu-VTt1-N2H7aV-D4,3136 -fastapi/security/utils.py,sha256=E9YIoez-H2k1oBLEdxqJEi8sV1umunJYKjQHvZG3FRY,261 -fastapi/sse.py,sha256=adtwP03ePndMQOuRCNRHrTfFQxMpRwrSUoRMHyB8OvA,6848 -fastapi/staticfiles.py,sha256=iirGIt3sdY2QZXd36ijs3Cj-T0FuGFda3cd90kM9Ikw,69 -fastapi/templating.py,sha256=4zsuTWgcjcEainMJFAlW6-gnslm6AgOS1SiiDWfmQxk,76 -fastapi/testclient.py,sha256=nBvaAmX66YldReJNZXPOk1sfuo2Q6hs8bOvIaCep6LQ,66 -fastapi/types.py,sha256=g2tD842BUHC2C3_P8P06albQ4MhCb9RybrSmp5rODgU,438 -fastapi/utils.py,sha256=DX0VrnMwfVsZxRz8IitQ42c2---fDzmFZkeRMZR2UMo,4341 -fastapi/websockets.py,sha256=419uncYObEKZG0YcrXscfQQYLSWoE10jqxVMetGdR98,222 diff --git a/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/REQUESTED b/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/WHEEL b/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/WHEEL deleted file mode 100644 index e651d8e..0000000 --- a/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: pdm-backend (2.4.9) -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/entry_points.txt b/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/entry_points.txt deleted file mode 100644 index b81849e..0000000 --- a/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/entry_points.txt +++ /dev/null @@ -1,5 +0,0 @@ -[console_scripts] -fastapi = fastapi.cli:main - -[gui_scripts] - diff --git a/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/licenses/LICENSE b/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/licenses/LICENSE deleted file mode 100644 index 3e92463..0000000 --- a/server/venv/Lib/site-packages/fastapi-0.138.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2018 Sebastián Ramírez - -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/server/venv/Lib/site-packages/fastapi/__init__.py b/server/venv/Lib/site-packages/fastapi/__init__.py deleted file mode 100644 index d7b99b5..0000000 --- a/server/venv/Lib/site-packages/fastapi/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -"""FastAPI framework, high performance, easy to learn, fast to code, ready for production""" - -__version__ = "0.138.0" - -from starlette import status as status - -from .applications import FastAPI as FastAPI -from .background import BackgroundTasks as BackgroundTasks -from .datastructures import UploadFile as UploadFile -from .exceptions import HTTPException as HTTPException -from .exceptions import WebSocketException as WebSocketException -from .param_functions import Body as Body -from .param_functions import Cookie as Cookie -from .param_functions import Depends as Depends -from .param_functions import File as File -from .param_functions import Form as Form -from .param_functions import Header as Header -from .param_functions import Path as Path -from .param_functions import Query as Query -from .param_functions import Security as Security -from .requests import Request as Request -from .responses import Response as Response -from .routing import APIRouter as APIRouter -from .websockets import WebSocket as WebSocket -from .websockets import WebSocketDisconnect as WebSocketDisconnect diff --git a/server/venv/Lib/site-packages/fastapi/__main__.py b/server/venv/Lib/site-packages/fastapi/__main__.py deleted file mode 100644 index fc36465..0000000 --- a/server/venv/Lib/site-packages/fastapi/__main__.py +++ /dev/null @@ -1,3 +0,0 @@ -from fastapi.cli import main - -main() diff --git a/server/venv/Lib/site-packages/fastapi/_compat/__init__.py b/server/venv/Lib/site-packages/fastapi/_compat/__init__.py deleted file mode 100644 index 4581c38..0000000 --- a/server/venv/Lib/site-packages/fastapi/_compat/__init__.py +++ /dev/null @@ -1,40 +0,0 @@ -from .shared import PYDANTIC_VERSION_MINOR_TUPLE as PYDANTIC_VERSION_MINOR_TUPLE -from .shared import annotation_is_pydantic_v1 as annotation_is_pydantic_v1 -from .shared import field_annotation_is_scalar as field_annotation_is_scalar -from .shared import ( - field_annotation_is_scalar_sequence as field_annotation_is_scalar_sequence, -) -from .shared import field_annotation_is_sequence as field_annotation_is_sequence -from .shared import ( - is_bytes_or_nonable_bytes_annotation as is_bytes_or_nonable_bytes_annotation, -) -from .shared import is_bytes_sequence_annotation as is_bytes_sequence_annotation -from .shared import is_pydantic_v1_model_instance as is_pydantic_v1_model_instance -from .shared import ( - is_uploadfile_or_nonable_uploadfile_annotation as is_uploadfile_or_nonable_uploadfile_annotation, -) -from .shared import ( - is_uploadfile_sequence_annotation as is_uploadfile_sequence_annotation, -) -from .shared import lenient_issubclass as lenient_issubclass -from .shared import sequence_types as sequence_types -from .shared import value_is_sequence as value_is_sequence -from .v2 import ModelField as ModelField -from .v2 import PydanticSchemaGenerationError as PydanticSchemaGenerationError -from .v2 import RequiredParam as RequiredParam -from .v2 import Undefined as Undefined -from .v2 import Url as Url -from .v2 import copy_field_info as copy_field_info -from .v2 import create_body_model as create_body_model -from .v2 import evaluate_forwardref as evaluate_forwardref -from .v2 import get_cached_model_fields as get_cached_model_fields -from .v2 import get_definitions as get_definitions -from .v2 import get_flat_models_from_fields as get_flat_models_from_fields -from .v2 import get_missing_field_error as get_missing_field_error -from .v2 import get_model_name_map as get_model_name_map -from .v2 import get_schema_from_model_field as get_schema_from_model_field -from .v2 import is_scalar_field as is_scalar_field -from .v2 import serialize_sequence_value as serialize_sequence_value -from .v2 import ( - with_info_plain_validator_function as with_info_plain_validator_function, -) diff --git a/server/venv/Lib/site-packages/fastapi/_compat/shared.py b/server/venv/Lib/site-packages/fastapi/_compat/shared.py deleted file mode 100644 index bd38c55..0000000 --- a/server/venv/Lib/site-packages/fastapi/_compat/shared.py +++ /dev/null @@ -1,214 +0,0 @@ -import types -import typing -import warnings -from collections import deque -from collections.abc import Mapping, Sequence -from dataclasses import is_dataclass -from typing import ( - Annotated, - Any, - TypeGuard, - TypeVar, - Union, - get_args, - get_origin, -) - -from fastapi.types import UnionType -from pydantic import BaseModel -from pydantic.version import VERSION as PYDANTIC_VERSION -from starlette.datastructures import UploadFile - -_T = TypeVar("_T") - -# Copy from Pydantic: pydantic/_internal/_typing_extra.py -WithArgsTypes: tuple[Any, ...] = ( - typing._GenericAlias, # type: ignore[attr-defined] # ty: ignore[unresolved-attribute] - types.GenericAlias, - types.UnionType, -) # pyright: ignore[reportAttributeAccessIssue] - -PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(".")[:2]) - - -sequence_annotation_to_type = { - Sequence: list, - list: list, - tuple: tuple, - set: set, - frozenset: frozenset, - deque: deque, -} - -sequence_types: tuple[type[Any], ...] = tuple(sequence_annotation_to_type.keys()) - - -# Copy of Pydantic: pydantic/_internal/_utils.py with added TypeGuard -def lenient_issubclass( - cls: Any, class_or_tuple: type[_T] | tuple[type[_T], ...] | None -) -> TypeGuard[type[_T]]: - try: - return isinstance(cls, type) and issubclass(cls, class_or_tuple) # type: ignore[arg-type] # ty: ignore[invalid-argument-type] - except TypeError: # pragma: no cover - if isinstance(cls, WithArgsTypes): - return False - raise # pragma: no cover - - -def _annotation_is_sequence(annotation: type[Any] | None) -> bool: - if lenient_issubclass(annotation, (str, bytes)): - return False - return lenient_issubclass(annotation, sequence_types) - - -def field_annotation_is_sequence(annotation: type[Any] | None) -> bool: - origin = get_origin(annotation) - if origin is Union or origin is UnionType: - for arg in get_args(annotation): - if field_annotation_is_sequence(arg): - return True - return False - return _annotation_is_sequence(annotation) or _annotation_is_sequence( - get_origin(annotation) - ) - - -def value_is_sequence(value: Any) -> bool: - return isinstance(value, sequence_types) and not isinstance(value, (str, bytes)) - - -def _annotation_is_complex(annotation: type[Any] | None) -> bool: - return ( - lenient_issubclass(annotation, (BaseModel, Mapping, UploadFile)) - or _annotation_is_sequence(annotation) - or is_dataclass(annotation) - ) - - -def field_annotation_is_complex(annotation: type[Any] | None) -> bool: - origin = get_origin(annotation) - if origin is Union or origin is UnionType: - return any(field_annotation_is_complex(arg) for arg in get_args(annotation)) - - if origin is Annotated: - return field_annotation_is_complex(get_args(annotation)[0]) - - return ( - _annotation_is_complex(annotation) - or _annotation_is_complex(origin) - or hasattr(origin, "__pydantic_core_schema__") - or hasattr(origin, "__get_pydantic_core_schema__") - ) - - -def field_annotation_is_scalar(annotation: Any) -> bool: - # handle Ellipsis here to make tuple[int, ...] work nicely - return annotation is Ellipsis or not field_annotation_is_complex(annotation) - - -def field_annotation_is_scalar_sequence(annotation: type[Any] | None) -> bool: - origin = get_origin(annotation) - if origin is Union or origin is UnionType: - at_least_one_scalar_sequence = False - for arg in get_args(annotation): - if field_annotation_is_scalar_sequence(arg): - at_least_one_scalar_sequence = True - continue - elif not field_annotation_is_scalar(arg): - return False - return at_least_one_scalar_sequence - return field_annotation_is_sequence(annotation) and all( - field_annotation_is_scalar(sub_annotation) - for sub_annotation in get_args(annotation) - ) - - -def is_bytes_or_nonable_bytes_annotation(annotation: Any) -> bool: - if lenient_issubclass(annotation, bytes): - return True - origin = get_origin(annotation) - if origin is Union or origin is UnionType: - for arg in get_args(annotation): - if lenient_issubclass(arg, bytes): - return True - return False - - -def is_uploadfile_or_nonable_uploadfile_annotation(annotation: Any) -> bool: - if lenient_issubclass(annotation, UploadFile): - return True - origin = get_origin(annotation) - if origin is Union or origin is UnionType: - for arg in get_args(annotation): - if lenient_issubclass(arg, UploadFile): - return True - return False - - -def is_bytes_sequence_annotation(annotation: Any) -> bool: - origin = get_origin(annotation) - if origin is Union or origin is UnionType: - at_least_one = False - for arg in get_args(annotation): - if is_bytes_sequence_annotation(arg): - at_least_one = True - continue - return at_least_one - return field_annotation_is_sequence(annotation) and all( - is_bytes_or_nonable_bytes_annotation(sub_annotation) - for sub_annotation in get_args(annotation) - ) - - -def is_uploadfile_sequence_annotation(annotation: Any) -> bool: - origin = get_origin(annotation) - if origin is Union or origin is UnionType: - at_least_one = False - for arg in get_args(annotation): - if is_uploadfile_sequence_annotation(arg): - at_least_one = True - continue - return at_least_one - return field_annotation_is_sequence(annotation) and all( - is_uploadfile_or_nonable_uploadfile_annotation(sub_annotation) - for sub_annotation in get_args(annotation) - ) - - -def is_pydantic_v1_model_instance(obj: Any) -> bool: - # TODO: remove this function once the required version of Pydantic fully - # removes pydantic.v1 - try: - with warnings.catch_warnings(): - warnings.simplefilter("ignore", UserWarning) - from pydantic import v1 - except ImportError: # pragma: no cover - return False - return isinstance(obj, v1.BaseModel) - - -def is_pydantic_v1_model_class(cls: Any) -> bool: - # TODO: remove this function once the required version of Pydantic fully - # removes pydantic.v1 - try: - with warnings.catch_warnings(): - warnings.simplefilter("ignore", UserWarning) - from pydantic import v1 - except ImportError: # pragma: no cover - return False - return lenient_issubclass(cls, v1.BaseModel) - - -def annotation_is_pydantic_v1(annotation: Any) -> bool: - if is_pydantic_v1_model_class(annotation): - return True - origin = get_origin(annotation) - if origin is Union or origin is UnionType: - for arg in get_args(annotation): - if is_pydantic_v1_model_class(arg): - return True - if field_annotation_is_sequence(annotation): - for sub_annotation in get_args(annotation): - if annotation_is_pydantic_v1(sub_annotation): - return True - return False diff --git a/server/venv/Lib/site-packages/fastapi/_compat/v2.py b/server/venv/Lib/site-packages/fastapi/_compat/v2.py deleted file mode 100644 index 7be686d..0000000 --- a/server/venv/Lib/site-packages/fastapi/_compat/v2.py +++ /dev/null @@ -1,493 +0,0 @@ -import re -import warnings -from collections.abc import Sequence -from copy import copy -from dataclasses import dataclass, is_dataclass -from enum import Enum -from functools import lru_cache -from typing import ( - Annotated, - Any, - Literal, - Union, - cast, - get_args, - get_origin, -) - -from fastapi._compat import lenient_issubclass, shared -from fastapi.openapi.constants import REF_TEMPLATE -from fastapi.types import IncEx, ModelNameMap, UnionType -from pydantic import BaseModel, ConfigDict, Field, TypeAdapter, create_model -from pydantic import PydanticSchemaGenerationError as PydanticSchemaGenerationError -from pydantic import PydanticUndefinedAnnotation as PydanticUndefinedAnnotation -from pydantic import ValidationError as ValidationError -from pydantic._internal import _typing_extra as _pydantic_typing_extra -from pydantic._internal._schema_generation_shared import ( # type: ignore[attr-defined] - GetJsonSchemaHandler as GetJsonSchemaHandler, -) -from pydantic.fields import FieldInfo as FieldInfo -from pydantic.json_schema import GenerateJsonSchema as _GenerateJsonSchema -from pydantic.json_schema import JsonSchemaValue as JsonSchemaValue -from pydantic_core import CoreSchema as CoreSchema -from pydantic_core import PydanticUndefined -from pydantic_core import Url as Url -from pydantic_core.core_schema import ( - with_info_plain_validator_function as with_info_plain_validator_function, -) - -RequiredParam = PydanticUndefined -Undefined = PydanticUndefined - - -def evaluate_forwardref( - value: Any, - globalns: dict[str, Any] | None = None, - localns: dict[str, Any] | None = None, -) -> Any: - # eval_type_lenient has been deprecated since Pydantic v2.10.0b1 (PR #10530) - try_eval_type = getattr(_pydantic_typing_extra, "try_eval_type", None) - if try_eval_type is not None: - return try_eval_type(value, globalns, localns)[0] - return _pydantic_typing_extra.eval_type_lenient( # ty: ignore[deprecated] - value, globalns, localns - ) - - -class GenerateJsonSchema(_GenerateJsonSchema): - # TODO: remove when this is merged (or equivalent): https://github.com/pydantic/pydantic/pull/12841 - # and dropping support for any version of Pydantic before that one (so, in a very long time) - def bytes_schema(self, schema: CoreSchema) -> JsonSchemaValue: - json_schema = {"type": "string", "contentMediaType": "application/octet-stream"} - bytes_mode = ( - self._config.ser_json_bytes - if self.mode == "serialization" - else self._config.val_json_bytes - ) - if bytes_mode == "base64": - json_schema["contentEncoding"] = "base64" - self.update_with_validations(json_schema, schema, self.ValidationsMapping.bytes) - return json_schema - - -# TODO: remove when dropping support for Pydantic < v2.12.3 -_Attrs = { - "default": ..., - "default_factory": None, - "alias": None, - "alias_priority": None, - "validation_alias": None, - "serialization_alias": None, - "title": None, - "field_title_generator": None, - "description": None, - "examples": None, - "exclude": None, - "exclude_if": None, - "discriminator": None, - "deprecated": None, - "json_schema_extra": None, - "frozen": None, - "validate_default": None, - "repr": True, - "init": None, - "init_var": None, - "kw_only": None, -} - - -# TODO: remove when dropping support for Pydantic < v2.12.3 -def asdict(field_info: FieldInfo) -> dict[str, Any]: - attributes = {} - for attr in _Attrs: - value = getattr(field_info, attr, Undefined) - if value is not Undefined: - attributes[attr] = value - return { - "annotation": field_info.annotation, - "metadata": field_info.metadata, - "attributes": attributes, - } - - -@dataclass -class ModelField: - field_info: FieldInfo - name: str - mode: Literal["validation", "serialization"] = "validation" - config: ConfigDict | None = None - - @property - def alias(self) -> str: - a = self.field_info.alias - return a if a is not None else self.name - - @property - def validation_alias(self) -> str | None: - va = self.field_info.validation_alias - if isinstance(va, str) and va: - return va - return None - - @property - def serialization_alias(self) -> str | None: - sa = self.field_info.serialization_alias - return sa or None - - @property - def default(self) -> Any: - return self.get_default() - - def __post_init__(self) -> None: - with warnings.catch_warnings(): - # Pydantic >= 2.12.0 warns about field specific metadata that is unused - # (e.g. `TypeAdapter(Annotated[int, Field(alias='b')])`). In some cases, we - # end up building the type adapter from a model field annotation so we - # need to ignore the warning: - if shared.PYDANTIC_VERSION_MINOR_TUPLE >= (2, 12): - from pydantic.warnings import UnsupportedFieldAttributeWarning - - warnings.simplefilter( - "ignore", category=UnsupportedFieldAttributeWarning - ) - # TODO: remove after setting the min Pydantic to v2.12.3 - # that adds asdict(), and use self.field_info.asdict() instead - field_dict = asdict(self.field_info) - annotated_args = ( - field_dict["annotation"], - *field_dict["metadata"], - # this FieldInfo needs to be created again so that it doesn't include - # the old field info metadata and only the rest of the attributes - Field(**field_dict["attributes"]), - ) - self._type_adapter: TypeAdapter[Any] = TypeAdapter( - Annotated[annotated_args], # ty: ignore[invalid-type-form] - config=self.config, - ) - - def get_default(self) -> Any: - if self.field_info.is_required(): - return Undefined - return self.field_info.get_default(call_default_factory=True) - - def validate( - self, - value: Any, - values: dict[str, Any] = {}, # noqa: B006 - *, - loc: tuple[int | str, ...] = (), - ) -> tuple[Any, list[dict[str, Any]]]: - try: - return ( - self._type_adapter.validate_python(value, from_attributes=True), - [], - ) - except ValidationError as exc: - return None, _regenerate_error_with_loc( - errors=exc.errors(include_url=False), loc_prefix=loc - ) - - def serialize( - self, - value: Any, - *, - mode: Literal["json", "python"] = "json", - include: IncEx | None = None, - exclude: IncEx | None = None, - by_alias: bool = True, - exclude_unset: bool = False, - exclude_defaults: bool = False, - exclude_none: bool = False, - ) -> Any: - # What calls this code passes a value that already called - # self._type_adapter.validate_python(value) - return self._type_adapter.dump_python( - value, - mode=mode, - include=include, - exclude=exclude, - by_alias=by_alias, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - ) - - def serialize_json( - self, - value: Any, - *, - include: IncEx | None = None, - exclude: IncEx | None = None, - by_alias: bool = True, - exclude_unset: bool = False, - exclude_defaults: bool = False, - exclude_none: bool = False, - ) -> bytes: - # What calls this code passes a value that already called - # self._type_adapter.validate_python(value) - # This uses Pydantic's dump_json() which serializes directly to JSON - # bytes in one pass (via Rust), avoiding the intermediate Python dict - # step of dump_python(mode="json") + json.dumps(). - return self._type_adapter.dump_json( - value, - include=include, - exclude=exclude, - by_alias=by_alias, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - ) - - def __hash__(self) -> int: - # Each ModelField is unique for our purposes, to allow making a dict from - # ModelField to its JSON Schema. - return id(self) - - -def _has_computed_fields(field: ModelField) -> bool: - computed_fields = field._type_adapter.core_schema.get("schema", {}).get( - "computed_fields", [] - ) - return len(computed_fields) > 0 - - -def get_schema_from_model_field( - *, - field: ModelField, - model_name_map: ModelNameMap, - field_mapping: dict[ - tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue - ], - separate_input_output_schemas: bool = True, -) -> dict[str, Any]: - override_mode: Literal["validation"] | None = ( - None - if (separate_input_output_schemas or _has_computed_fields(field)) - else "validation" - ) - field_alias = ( - (field.validation_alias or field.alias) - if field.mode == "validation" - else (field.serialization_alias or field.alias) - ) - - # This expects that GenerateJsonSchema was already used to generate the definitions - json_schema = field_mapping[(field, override_mode or field.mode)] - if "$ref" not in json_schema: - # TODO remove when deprecating Pydantic v1 - # Ref: https://github.com/pydantic/pydantic/blob/d61792cc42c80b13b23e3ffa74bc37ec7c77f7d1/pydantic/schema.py#L207 - json_schema["title"] = field.field_info.title or field_alias.title().replace( - "_", " " - ) - return json_schema - - -def get_definitions( - *, - fields: Sequence[ModelField], - model_name_map: ModelNameMap, - separate_input_output_schemas: bool = True, -) -> tuple[ - dict[tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue], - dict[str, dict[str, Any]], -]: - schema_generator = GenerateJsonSchema(ref_template=REF_TEMPLATE) - validation_fields = [field for field in fields if field.mode == "validation"] - serialization_fields = [field for field in fields if field.mode == "serialization"] - flat_validation_models = get_flat_models_from_fields( - validation_fields, known_models=set() - ) - flat_serialization_models = get_flat_models_from_fields( - serialization_fields, known_models=set() - ) - flat_validation_model_fields = [ - ModelField( - field_info=FieldInfo(annotation=model), - name=model.__name__, - mode="validation", - ) - for model in flat_validation_models - ] - flat_serialization_model_fields = [ - ModelField( - field_info=FieldInfo(annotation=model), - name=model.__name__, - mode="serialization", - ) - for model in flat_serialization_models - ] - flat_model_fields = flat_validation_model_fields + flat_serialization_model_fields - input_types = {f.field_info.annotation for f in fields} - unique_flat_model_fields = { - f for f in flat_model_fields if f.field_info.annotation not in input_types - } - inputs = [ - ( - field, - ( - field.mode - if (separate_input_output_schemas or _has_computed_fields(field)) - else "validation" - ), - field._type_adapter.core_schema, - ) - for field in list(fields) + list(unique_flat_model_fields) - ] - field_mapping, definitions = schema_generator.generate_definitions(inputs=inputs) - for item_def in cast(dict[str, dict[str, Any]], definitions).values(): - if "description" in item_def: - item_description = cast(str, item_def["description"]).split("\f")[0] - item_def["description"] = item_description - # definitions: dict[DefsRef, dict[str, Any]] - # but mypy complains about general str in other places that are not declared as - # DefsRef, although DefsRef is just str: - # DefsRef = NewType('DefsRef', str) - # So, a cast to simplify the types here - return field_mapping, cast(dict[str, dict[str, Any]], definitions) - - -def is_scalar_field(field: ModelField) -> bool: - from fastapi import params - - return shared.field_annotation_is_scalar( - field.field_info.annotation - ) and not isinstance(field.field_info, params.Body) - - -def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo: - cls = type(field_info) - merged_field_info = cls.from_annotation(annotation) - new_field_info = copy(field_info) - new_field_info.metadata = merged_field_info.metadata - new_field_info.annotation = merged_field_info.annotation - return new_field_info - - -def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]: - origin_type = get_origin(field.field_info.annotation) or field.field_info.annotation - if origin_type is Union or origin_type is UnionType: # Handle optional sequences - union_args = get_args(field.field_info.annotation) - for union_arg in union_args: - if union_arg is type(None): - continue - origin_type = get_origin(union_arg) or union_arg - break - assert issubclass(origin_type, shared.sequence_types) # type: ignore[arg-type] # ty: ignore[invalid-argument-type] - return shared.sequence_annotation_to_type[origin_type](value) # type: ignore[no-any-return,index] # ty: ignore[invalid-return-type] - - -def get_missing_field_error(loc: tuple[int | str, ...]) -> dict[str, Any]: - error = ValidationError.from_exception_data( - "Field required", [{"type": "missing", "loc": loc, "input": {}}] - ).errors(include_url=False)[0] - error["input"] = None - return error # type: ignore[return-value] # ty: ignore[invalid-return-type] - - -def create_body_model( - *, fields: Sequence[ModelField], model_name: str -) -> type[BaseModel]: - field_params = {f.name: (f.field_info.annotation, f.field_info) for f in fields} - BodyModel: type[BaseModel] = create_model(model_name, **field_params) # type: ignore[call-overload] # ty: ignore[no-matching-overload] - return BodyModel - - -def get_model_fields(model: type[BaseModel]) -> list[ModelField]: - model_fields: list[ModelField] = [] - for name, field_info in model.model_fields.items(): - type_ = field_info.annotation - if lenient_issubclass(type_, (BaseModel, dict)) or is_dataclass(type_): - model_config = None - else: - model_config = model.model_config - model_fields.append( - ModelField( - field_info=field_info, - name=name, - config=model_config, - ) - ) - return model_fields - - -@lru_cache -def get_cached_model_fields(model: type[BaseModel]) -> list[ModelField]: - return get_model_fields(model) - - -# Duplicate of several schema functions from Pydantic v1 to make them compatible with -# Pydantic v2 and allow mixing the models - -TypeModelOrEnum = type["BaseModel"] | type[Enum] -TypeModelSet = set[TypeModelOrEnum] - - -def normalize_name(name: str) -> str: - return re.sub(r"[^a-zA-Z0-9.\-_]", "_", name) - - -def get_model_name_map(unique_models: TypeModelSet) -> dict[TypeModelOrEnum, str]: - name_model_map = {} - for model in unique_models: - model_name = normalize_name(model.__name__) - name_model_map[model_name] = model - return {v: k for k, v in name_model_map.items()} - - -def get_flat_models_from_model( - model: type["BaseModel"], known_models: TypeModelSet | None = None -) -> TypeModelSet: - known_models = known_models or set() - fields = get_model_fields(model) - get_flat_models_from_fields(fields, known_models=known_models) - return known_models - - -def get_flat_models_from_annotation( - annotation: Any, known_models: TypeModelSet -) -> TypeModelSet: - origin = get_origin(annotation) - if origin is not None: - for arg in get_args(annotation): - if lenient_issubclass(arg, (BaseModel, Enum)): - if arg not in known_models: - known_models.add(arg) # type: ignore[arg-type] - if lenient_issubclass(arg, BaseModel): - get_flat_models_from_model(arg, known_models=known_models) - else: - get_flat_models_from_annotation(arg, known_models=known_models) - return known_models - - -def get_flat_models_from_field( - field: ModelField, known_models: TypeModelSet -) -> TypeModelSet: - field_type = field.field_info.annotation - if lenient_issubclass(field_type, BaseModel): - if field_type in known_models: - return known_models - known_models.add(field_type) - get_flat_models_from_model(field_type, known_models=known_models) - elif lenient_issubclass(field_type, Enum): - known_models.add(field_type) - else: - get_flat_models_from_annotation(field_type, known_models=known_models) - return known_models - - -def get_flat_models_from_fields( - fields: Sequence[ModelField], known_models: TypeModelSet -) -> TypeModelSet: - for field in fields: - get_flat_models_from_field(field, known_models=known_models) - return known_models - - -def _regenerate_error_with_loc( - *, errors: Sequence[Any], loc_prefix: tuple[str | int, ...] -) -> list[dict[str, Any]]: - updated_loc_errors: list[Any] = [ - {**err, "loc": loc_prefix + err.get("loc", ())} for err in errors - ] - - return updated_loc_errors diff --git a/server/venv/Lib/site-packages/fastapi/applications.py b/server/venv/Lib/site-packages/fastapi/applications.py deleted file mode 100644 index 56e1a3e..0000000 --- a/server/venv/Lib/site-packages/fastapi/applications.py +++ /dev/null @@ -1,4768 +0,0 @@ -import os -from collections.abc import Awaitable, Callable, Coroutine, Sequence -from enum import Enum -from typing import Annotated, Any, Literal, TypeVar - -from annotated_doc import Doc -from fastapi import routing -from fastapi.datastructures import Default, DefaultPlaceholder -from fastapi.exception_handlers import ( - http_exception_handler, - request_validation_exception_handler, - websocket_request_validation_exception_handler, -) -from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError -from fastapi.logger import logger -from fastapi.middleware.asyncexitstack import AsyncExitStackMiddleware -from fastapi.openapi.docs import ( - get_redoc_html, - get_swagger_ui_html, - get_swagger_ui_oauth2_redirect_html, -) -from fastapi.openapi.utils import get_openapi -from fastapi.params import Depends -from fastapi.types import DecoratedCallable, IncEx -from fastapi.utils import generate_unique_id -from starlette.applications import Starlette -from starlette.datastructures import State -from starlette.exceptions import HTTPException -from starlette.middleware import Middleware -from starlette.middleware.base import BaseHTTPMiddleware -from starlette.middleware.errors import ServerErrorMiddleware -from starlette.middleware.exceptions import ExceptionMiddleware -from starlette.requests import Request -from starlette.responses import HTMLResponse, JSONResponse, Response -from starlette.routing import BaseRoute -from starlette.types import ASGIApp, ExceptionHandler, Lifespan, Receive, Scope, Send -from typing_extensions import deprecated - -AppType = TypeVar("AppType", bound="FastAPI") - - -class FastAPI(Starlette): - """ - `FastAPI` app class, the main entrypoint to use FastAPI. - - Read more in the - [FastAPI docs for First Steps](https://fastapi.tiangolo.com/tutorial/first-steps/). - - ## Example - - ```python - from fastapi import FastAPI - - app = FastAPI() - ``` - """ - - def __init__( - self: AppType, - *, - debug: Annotated[ - bool, - Doc( - """ - Boolean indicating if debug tracebacks should be returned on server - errors. - - Read more in the - [Starlette docs for Applications](https://www.starlette.dev/applications/#instantiating-the-application). - """ - ), - ] = False, - routes: Annotated[ - list[BaseRoute] | None, - Doc( - """ - **Note**: you probably shouldn't use this parameter, it is inherited - from Starlette and supported for compatibility. - - --- - - A list of routes to serve incoming HTTP and WebSocket requests. - """ - ), - deprecated( - """ - You normally wouldn't use this parameter with FastAPI, it is inherited - from Starlette and supported for compatibility. - - In FastAPI, you normally would use the *path operation methods*, - like `app.get()`, `app.post()`, etc. - """ - ), - ] = None, - title: Annotated[ - str, - Doc( - """ - The title of the API. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more in the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI(title="ChimichangApp") - ``` - """ - ), - ] = "FastAPI", - summary: Annotated[ - str | None, - Doc( - """ - A short summary of the API. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more in the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI(summary="Deadpond's favorite app. Nuff said.") - ``` - """ - ), - ] = None, - description: Annotated[ - str, - Doc( - ''' - A description of the API. Supports Markdown (using - [CommonMark syntax](https://commonmark.org/)). - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more in the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI( - description=""" - ChimichangApp API helps you do awesome stuff. 🚀 - - ## Items - - You can **read items**. - - ## Users - - You will be able to: - - * **Create users** (_not implemented_). - * **Read users** (_not implemented_). - - """ - ) - ``` - ''' - ), - ] = "", - version: Annotated[ - str, - Doc( - """ - The version of the API. - - **Note** This is the version of your application, not the version of - the OpenAPI specification nor the version of FastAPI being used. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more in the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI(version="0.0.1") - ``` - """ - ), - ] = "0.1.0", - openapi_url: Annotated[ - str | None, - Doc( - """ - The URL where the OpenAPI schema will be served from. - - If you set it to `None`, no OpenAPI schema will be served publicly, and - the default automatic endpoints `/docs` and `/redoc` will also be - disabled. - - Read more in the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#openapi-url). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI(openapi_url="/api/v1/openapi.json") - ``` - """ - ), - ] = "/openapi.json", - openapi_tags: Annotated[ - list[dict[str, Any]] | None, - Doc( - """ - A list of tags used by OpenAPI, these are the same `tags` you can set - in the *path operations*, like: - - * `@app.get("/users/", tags=["users"])` - * `@app.get("/items/", tags=["items"])` - - The order of the tags can be used to specify the order shown in - tools like Swagger UI, used in the automatic path `/docs`. - - It's not required to specify all the tags used. - - The tags that are not declared MAY be organized randomly or based - on the tools' logic. Each tag name in the list MUST be unique. - - The value of each item is a `dict` containing: - - * `name`: The name of the tag. - * `description`: A short description of the tag. - [CommonMark syntax](https://commonmark.org/) MAY be used for rich - text representation. - * `externalDocs`: Additional external documentation for this tag. If - provided, it would contain a `dict` with: - * `description`: A short description of the target documentation. - [CommonMark syntax](https://commonmark.org/) MAY be used for - rich text representation. - * `url`: The URL for the target documentation. Value MUST be in - the form of a URL. - - Read more in the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-tags). - - **Example** - - ```python - from fastapi import FastAPI - - tags_metadata = [ - { - "name": "users", - "description": "Operations with users. The **login** logic is also here.", - }, - { - "name": "items", - "description": "Manage items. So _fancy_ they have their own docs.", - "externalDocs": { - "description": "Items external docs", - "url": "https://fastapi.tiangolo.com/", - }, - }, - ] - - app = FastAPI(openapi_tags=tags_metadata) - ``` - """ - ), - ] = None, - servers: Annotated[ - list[dict[str, str | Any]] | None, - Doc( - """ - A `list` of `dict`s with connectivity information to a target server. - - You would use it, for example, if your application is served from - different domains and you want to use the same Swagger UI in the - browser to interact with each of them (instead of having multiple - browser tabs open). Or if you want to leave fixed the possible URLs. - - If the servers `list` is not provided, or is an empty `list`, the - `servers` property in the generated OpenAPI will be: - - * a `dict` with a `url` value of the application's mounting point - (`root_path`) if it's different from `/`. - * otherwise, the `servers` property will be omitted from the OpenAPI - schema. - - Each item in the `list` is a `dict` containing: - - * `url`: A URL to the target host. This URL supports Server Variables - and MAY be relative, to indicate that the host location is relative - to the location where the OpenAPI document is being served. Variable - substitutions will be made when a variable is named in `{`brackets`}`. - * `description`: An optional string describing the host designated by - the URL. [CommonMark syntax](https://commonmark.org/) MAY be used for - rich text representation. - * `variables`: A `dict` between a variable name and its value. The value - is used for substitution in the server's URL template. - - Read more in the - [FastAPI docs for Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/#additional-servers). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI( - servers=[ - {"url": "https://stag.example.com", "description": "Staging environment"}, - {"url": "https://prod.example.com", "description": "Production environment"}, - ] - ) - ``` - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[Depends] | None, - Doc( - """ - A list of global dependencies, they will be applied to each - *path operation*, including in sub-routers. - - Read more about it in the - [FastAPI docs for Global Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/global-dependencies/). - - **Example** - - ```python - from fastapi import Depends, FastAPI - - from .dependencies import func_dep_1, func_dep_2 - - app = FastAPI(dependencies=[Depends(func_dep_1), Depends(func_dep_2)]) - ``` - """ - ), - ] = None, - default_response_class: Annotated[ - type[Response], - Doc( - """ - The default response class to be used. - - Read more in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class). - - **Example** - - ```python - from fastapi import FastAPI - from fastapi.responses import ORJSONResponse - - app = FastAPI(default_response_class=ORJSONResponse) - ``` - """ - ), - ] = Default(JSONResponse), - redirect_slashes: Annotated[ - bool, - Doc( - """ - Whether to detect and redirect slashes in URLs when the client doesn't - use the same format. - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI(redirect_slashes=True) # the default - - @app.get("/items/") - async def read_items(): - return [{"item_id": "Foo"}] - ``` - - With this app, if a client goes to `/items` (without a trailing slash), - they will be automatically redirected with an HTTP status code of 307 - to `/items/`. - """ - ), - ] = True, - docs_url: Annotated[ - str | None, - Doc( - """ - The path to the automatic interactive API documentation. - It is handled in the browser by Swagger UI. - - The default URL is `/docs`. You can disable it by setting it to `None`. - - If `openapi_url` is set to `None`, this will be automatically disabled. - - Read more in the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#docs-urls). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI(docs_url="/documentation", redoc_url=None) - ``` - """ - ), - ] = "/docs", - redoc_url: Annotated[ - str | None, - Doc( - """ - The path to the alternative automatic interactive API documentation - provided by ReDoc. - - The default URL is `/redoc`. You can disable it by setting it to `None`. - - If `openapi_url` is set to `None`, this will be automatically disabled. - - Read more in the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#docs-urls). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI(docs_url="/documentation", redoc_url="redocumentation") - ``` - """ - ), - ] = "/redoc", - swagger_ui_oauth2_redirect_url: Annotated[ - str | None, - Doc( - """ - The OAuth2 redirect endpoint for the Swagger UI. - - By default it is `/docs/oauth2-redirect`. - - This is only used if you use OAuth2 (with the "Authorize" button) - with Swagger UI. - """ - ), - ] = "/docs/oauth2-redirect", - swagger_ui_init_oauth: Annotated[ - dict[str, Any] | None, - Doc( - """ - OAuth2 configuration for the Swagger UI, by default shown at `/docs`. - - Read more about the available configuration options in the - [Swagger UI docs](https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/). - """ - ), - ] = None, - middleware: Annotated[ - Sequence[Middleware] | None, - Doc( - """ - List of middleware to be added when creating the application. - - In FastAPI you would normally do this with `app.add_middleware()` - instead. - - Read more in the - [FastAPI docs for Middleware](https://fastapi.tiangolo.com/tutorial/middleware/). - """ - ), - ] = None, - exception_handlers: Annotated[ - dict[ - int | type[Exception], - Callable[[Request, Any], Coroutine[Any, Any, Response]], - ] - | None, - Doc( - """ - A dictionary with handlers for exceptions. - - In FastAPI, you would normally use the decorator - `@app.exception_handler()`. - - Read more in the - [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/). - """ - ), - ] = None, - on_startup: Annotated[ - Sequence[Callable[[], Any]] | None, - Doc( - """ - A list of startup event handler functions. - - You should instead use the `lifespan` handlers. - - Read more in the [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/). - """ - ), - ] = None, - on_shutdown: Annotated[ - Sequence[Callable[[], Any]] | None, - Doc( - """ - A list of shutdown event handler functions. - - You should instead use the `lifespan` handlers. - - Read more in the - [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/). - """ - ), - ] = None, - lifespan: Annotated[ - Lifespan[AppType] | None, - Doc( - """ - A `Lifespan` context manager handler. This replaces `startup` and - `shutdown` functions with a single context manager. - - Read more in the - [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/). - """ - ), - ] = None, - terms_of_service: Annotated[ - str | None, - Doc( - """ - A URL to the Terms of Service for your API. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more at the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). - - **Example** - - ```python - app = FastAPI(terms_of_service="http://example.com/terms/") - ``` - """ - ), - ] = None, - contact: Annotated[ - dict[str, str | Any] | None, - Doc( - """ - A dictionary with the contact information for the exposed API. - - It can contain several fields. - - * `name`: (`str`) The name of the contact person/organization. - * `url`: (`str`) A URL pointing to the contact information. MUST be in - the format of a URL. - * `email`: (`str`) The email address of the contact person/organization. - MUST be in the format of an email address. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more at the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). - - **Example** - - ```python - app = FastAPI( - contact={ - "name": "Deadpoolio the Amazing", - "url": "http://x-force.example.com/contact/", - "email": "dp@x-force.example.com", - } - ) - ``` - """ - ), - ] = None, - license_info: Annotated[ - dict[str, str | Any] | None, - Doc( - """ - A dictionary with the license information for the exposed API. - - It can contain several fields. - - * `name`: (`str`) **REQUIRED** (if a `license_info` is set). The - license name used for the API. - * `identifier`: (`str`) An [SPDX](https://spdx.dev/) license expression - for the API. The `identifier` field is mutually exclusive of the `url` - field. Available since OpenAPI 3.1.0, FastAPI 0.99.0. - * `url`: (`str`) A URL to the license used for the API. This MUST be - the format of a URL. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more at the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). - - **Example** - - ```python - app = FastAPI( - license_info={ - "name": "Apache 2.0", - "url": "https://www.apache.org/licenses/LICENSE-2.0.html", - } - ) - ``` - """ - ), - ] = None, - openapi_prefix: Annotated[ - str, - Doc( - """ - A URL prefix for the OpenAPI URL. - """ - ), - deprecated( - """ - "openapi_prefix" has been deprecated in favor of "root_path", which - follows more closely the ASGI standard, is simpler, and more - automatic. - """ - ), - ] = "", - root_path: Annotated[ - str, - Doc( - """ - A path prefix handled by a proxy that is not seen by the application - but is seen by external clients, which affects things like Swagger UI. - - Read more about it at the - [FastAPI docs for Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI(root_path="/api/v1") - ``` - """ - ), - ] = "", - root_path_in_servers: Annotated[ - bool, - Doc( - """ - To disable automatically generating the URLs in the `servers` field - in the autogenerated OpenAPI using the `root_path`. - - Read more about it in the - [FastAPI docs for Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/#disable-automatic-server-from-root-path). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI(root_path_in_servers=False) - ``` - """ - ), - ] = True, - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses to be shown in OpenAPI. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/). - - And in the - [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - OpenAPI callbacks that should apply to all *path operations*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - webhooks: Annotated[ - routing.APIRouter | None, - Doc( - """ - Add OpenAPI webhooks. This is similar to `callbacks` but it doesn't - depend on specific *path operations*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - **Note**: This is available since OpenAPI 3.1.0, FastAPI 0.99.0. - - Read more about it in the - [FastAPI docs for OpenAPI Webhooks](https://fastapi.tiangolo.com/advanced/openapi-webhooks/). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark all *path operations* as deprecated. You probably don't need it, - but it's available. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#deprecate-a-path-operation). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - To include (or not) all the *path operations* in the generated OpenAPI. - You probably don't need it, but it's available. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - swagger_ui_parameters: Annotated[ - dict[str, Any] | None, - Doc( - """ - Parameters to configure Swagger UI, the autogenerated interactive API - documentation (by default at `/docs`). - - Read more about it in the - [FastAPI docs about how to Configure Swagger UI](https://fastapi.tiangolo.com/how-to/configure-swagger-ui/). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - separate_input_output_schemas: Annotated[ - bool, - Doc( - """ - Whether to generate separate OpenAPI schemas for request body and - response body when the results would be more precise. - - This is particularly useful when automatically generating clients. - - For example, if you have a model like: - - ```python - from pydantic import BaseModel - - class Item(BaseModel): - name: str - tags: list[str] = [] - ``` - - When `Item` is used for input, a request body, `tags` is not required, - the client doesn't have to provide it. - - But when using `Item` for output, for a response body, `tags` is always - available because it has a default value, even if it's just an empty - list. So, the client should be able to always expect it. - - In this case, there would be two different schemas, one for input and - another one for output. - - Read more about it in the - [FastAPI docs about how to separate schemas for input and output](https://fastapi.tiangolo.com/how-to/separate-openapi-schemas) - """ - ), - ] = True, - openapi_external_docs: Annotated[ - dict[str, Any] | None, - Doc( - """ - This field allows you to provide additional external documentation links. - If provided, it must be a dictionary containing: - - * `description`: A brief description of the external documentation. - * `url`: The URL pointing to the external documentation. The value **MUST** - be a valid URL format. - - **Example**: - - ```python - from fastapi import FastAPI - - external_docs = { - "description": "Detailed API Reference", - "url": "https://example.com/api-docs", - } - - app = FastAPI(openapi_external_docs=external_docs) - ``` - """ - ), - ] = None, - strict_content_type: Annotated[ - bool, - Doc( - """ - Enable strict checking for request Content-Type headers. - - When `True` (the default), requests with a body that do not include - a `Content-Type` header will **not** be parsed as JSON. - - This prevents potential cross-site request forgery (CSRF) attacks - that exploit the browser's ability to send requests without a - Content-Type header, bypassing CORS preflight checks. In particular - applicable for apps that need to be run locally (in localhost). - - When `False`, requests without a `Content-Type` header will have - their body parsed as JSON, which maintains compatibility with - certain clients that don't send `Content-Type` headers. - - Read more about it in the - [FastAPI docs for Strict Content-Type](https://fastapi.tiangolo.com/advanced/strict-content-type/). - """ - ), - ] = True, - **extra: Annotated[ - Any, - Doc( - """ - Extra keyword arguments to be stored in the app, not used by FastAPI - anywhere. - """ - ), - ], - ) -> None: - self.debug = debug - self.title = title - self.summary = summary - self.description = description - self.version = version - self.terms_of_service = terms_of_service - self.contact = contact - self.license_info = license_info - self.openapi_url = openapi_url - self.openapi_tags = openapi_tags - self.root_path_in_servers = root_path_in_servers - self.docs_url = docs_url - self.redoc_url = redoc_url - self.swagger_ui_oauth2_redirect_url = swagger_ui_oauth2_redirect_url - self.swagger_ui_init_oauth = swagger_ui_init_oauth - self.swagger_ui_parameters = swagger_ui_parameters - self.servers = servers or [] - self.separate_input_output_schemas = separate_input_output_schemas - self.openapi_external_docs = openapi_external_docs - self.extra = extra - self.openapi_version: Annotated[ - str, - Doc( - """ - The version string of OpenAPI. - - FastAPI will generate OpenAPI version 3.1.0, and will output that as - the OpenAPI version. But some tools, even though they might be - compatible with OpenAPI 3.1.0, might not recognize it as a valid. - - So you could override this value to trick those tools into using - the generated OpenAPI. Have in mind that this is a hack. But if you - avoid using features added in OpenAPI 3.1.0, it might work for your - use case. - - This is not passed as a parameter to the `FastAPI` class to avoid - giving the false idea that FastAPI would generate a different OpenAPI - schema. It is only available as an attribute. - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI() - - app.openapi_version = "3.0.2" - ``` - """ - ), - ] = "3.1.0" - self.openapi_schema: dict[str, Any] | None = None - self._openapi_routes_version: int | None = None - if self.openapi_url: - assert self.title, "A title must be provided for OpenAPI, e.g.: 'My API'" - assert self.version, "A version must be provided for OpenAPI, e.g.: '2.1.0'" - # TODO: remove when discarding the openapi_prefix parameter - if openapi_prefix: - logger.warning( - '"openapi_prefix" has been deprecated in favor of "root_path", which ' - "follows more closely the ASGI standard, is simpler, and more " - "automatic. Check the docs at " - "https://fastapi.tiangolo.com/advanced/sub-applications/" - ) - self.webhooks: Annotated[ - routing.APIRouter, - Doc( - """ - The `app.webhooks` attribute is an `APIRouter` with the *path - operations* that will be used just for documentation of webhooks. - - Read more about it in the - [FastAPI docs for OpenAPI Webhooks](https://fastapi.tiangolo.com/advanced/openapi-webhooks/). - """ - ), - ] = webhooks or routing.APIRouter() - self.root_path = root_path or openapi_prefix - self.state: Annotated[ - State, - Doc( - """ - A state object for the application. This is the same object for the - entire application, it doesn't change from request to request. - - You normally wouldn't use this in FastAPI, for most of the cases you - would instead use FastAPI dependencies. - - This is simply inherited from Starlette. - - Read more about it in the - [Starlette docs for Applications](https://www.starlette.dev/applications/#storing-state-on-the-app-instance). - """ - ), - ] = State() - self.dependency_overrides: Annotated[ - dict[Callable[..., Any], Callable[..., Any]], - Doc( - """ - A dictionary with overrides for the dependencies. - - Each key is the original dependency callable, and the value is the - actual dependency that should be called. - - This is for testing, to replace expensive dependencies with testing - versions. - - Read more about it in the - [FastAPI docs for Testing Dependencies with Overrides](https://fastapi.tiangolo.com/advanced/testing-dependencies/). - """ - ), - ] = {} - self.router: routing.APIRouter = routing.APIRouter( - routes=routes, - redirect_slashes=redirect_slashes, - dependency_overrides_provider=self, - on_startup=on_startup, - on_shutdown=on_shutdown, - lifespan=lifespan, - default_response_class=default_response_class, - dependencies=dependencies, - callbacks=callbacks, - deprecated=deprecated, - include_in_schema=include_in_schema, - responses=responses, - generate_unique_id_function=generate_unique_id_function, - strict_content_type=strict_content_type, - ) - self.exception_handlers: dict[ - Any, Callable[[Request, Any], Response | Awaitable[Response]] - ] = {} if exception_handlers is None else dict(exception_handlers) - self.exception_handlers.setdefault(HTTPException, http_exception_handler) - self.exception_handlers.setdefault( - RequestValidationError, request_validation_exception_handler - ) - - # Starlette still has incorrect type specification for the handlers - self.exception_handlers.setdefault( - WebSocketRequestValidationError, - websocket_request_validation_exception_handler, # type: ignore[arg-type] - ) # ty: ignore[no-matching-overload] - - self.user_middleware: list[Middleware] = ( - [] if middleware is None else list(middleware) - ) - self.middleware_stack: ASGIApp | None = None - self.setup() - - def build_middleware_stack(self) -> ASGIApp: - # Duplicate/override from Starlette to add AsyncExitStackMiddleware - # inside of ExceptionMiddleware, inside of custom user middlewares - debug = self.debug - error_handler = None - exception_handlers: dict[Any, ExceptionHandler] = {} - - for key, value in self.exception_handlers.items(): - if key in (500, Exception): - error_handler = value - else: - exception_handlers[key] = value - - middleware = ( - [Middleware(ServerErrorMiddleware, handler=error_handler, debug=debug)] - + self.user_middleware - + [ - Middleware( - ExceptionMiddleware, - handlers=exception_handlers, - debug=debug, - ), - # Add FastAPI-specific AsyncExitStackMiddleware for closing files. - # Before this was also used for closing dependencies with yield but - # those now have their own AsyncExitStack, to properly support - # streaming responses while keeping compatibility with the previous - # versions (as of writing 0.117.1) that allowed doing - # except HTTPException inside a dependency with yield. - # This needs to happen after user middlewares because those create a - # new contextvars context copy by using a new AnyIO task group. - # This AsyncExitStack preserves the context for contextvars, not - # strictly necessary for closing files but it was one of the original - # intentions. - # If the AsyncExitStack lived outside of the custom middlewares and - # contextvars were set, for example in a dependency with 'yield' - # in that internal contextvars context, the values would not be - # available in the outer context of the AsyncExitStack. - # By placing the middleware and the AsyncExitStack here, inside all - # user middlewares, the same context is used. - # This is currently not needed, only for closing files, but used to be - # important when dependencies with yield were closed here. - Middleware(AsyncExitStackMiddleware), - ] - ) - - app = self.router - for cls, args, kwargs in reversed(middleware): - app = cls(app, *args, **kwargs) - return app - - def openapi(self) -> dict[str, Any]: - """ - Generate the OpenAPI schema of the application. This is called by FastAPI - internally. - - The first time it is called it stores the result in the attribute - `app.openapi_schema`, and next times it is called, it just returns that same - result. To avoid the cost of generating the schema every time. - - If you need to modify the generated OpenAPI schema, you could modify it. - - Read more in the - [FastAPI docs for OpenAPI](https://fastapi.tiangolo.com/how-to/extending-openapi/). - """ - routes_version = self.router._get_routes_version() - if not self.openapi_schema or self._openapi_routes_version != routes_version: - self.openapi_schema = get_openapi( - title=self.title, - version=self.version, - openapi_version=self.openapi_version, - summary=self.summary, - description=self.description, - terms_of_service=self.terms_of_service, - contact=self.contact, - license_info=self.license_info, - routes=self.routes, - webhooks=self.webhooks.routes, - tags=self.openapi_tags, - servers=self.servers, - separate_input_output_schemas=self.separate_input_output_schemas, - external_docs=self.openapi_external_docs, - ) - self._openapi_routes_version = routes_version - return self.openapi_schema - - def setup(self) -> None: - if self.openapi_url: - - async def openapi(req: Request) -> JSONResponse: - root_path = req.scope.get("root_path", "").rstrip("/") - schema = self.openapi() - if root_path and self.root_path_in_servers: - server_urls = {s.get("url") for s in schema.get("servers", [])} - if root_path not in server_urls: - schema = dict(schema) - schema["servers"] = [{"url": root_path}] + schema.get( - "servers", [] - ) - return JSONResponse(schema) - - self.add_route(self.openapi_url, openapi, include_in_schema=False) - if self.openapi_url and self.docs_url: - - async def swagger_ui_html(req: Request) -> HTMLResponse: - root_path = req.scope.get("root_path", "").rstrip("/") - openapi_url = root_path + self.openapi_url - oauth2_redirect_url = self.swagger_ui_oauth2_redirect_url - if oauth2_redirect_url: - oauth2_redirect_url = root_path + oauth2_redirect_url - return get_swagger_ui_html( - openapi_url=openapi_url, - title=f"{self.title} - Swagger UI", - oauth2_redirect_url=oauth2_redirect_url, - init_oauth=self.swagger_ui_init_oauth, - swagger_ui_parameters=self.swagger_ui_parameters, - ) - - self.add_route(self.docs_url, swagger_ui_html, include_in_schema=False) - - if self.swagger_ui_oauth2_redirect_url: - - async def swagger_ui_redirect(req: Request) -> HTMLResponse: - return get_swagger_ui_oauth2_redirect_html() - - self.add_route( - self.swagger_ui_oauth2_redirect_url, - swagger_ui_redirect, - include_in_schema=False, - ) - if self.openapi_url and self.redoc_url: - - async def redoc_html(req: Request) -> HTMLResponse: - root_path = req.scope.get("root_path", "").rstrip("/") - openapi_url = root_path + self.openapi_url - return get_redoc_html( - openapi_url=openapi_url, title=f"{self.title} - ReDoc" - ) - - self.add_route(self.redoc_url, redoc_html, include_in_schema=False) - - async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: - if self.root_path: - scope["root_path"] = self.root_path - await super().__call__(scope, receive, send) - - def add_api_route( - self, - path: str, - endpoint: Callable[..., Any], - *, - response_model: Any = Default(None), - status_code: int | None = None, - tags: list[str | Enum] | None = None, - dependencies: Sequence[Depends] | None = None, - summary: str | None = None, - description: str | None = None, - response_description: str = "Successful Response", - responses: dict[int | str, dict[str, Any]] | None = None, - deprecated: bool | None = None, - methods: list[str] | None = None, - operation_id: str | None = None, - response_model_include: IncEx | None = None, - response_model_exclude: IncEx | None = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: type[Response] | DefaultPlaceholder = Default(JSONResponse), - name: str | None = None, - openapi_extra: dict[str, Any] | None = None, - generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( - generate_unique_id - ), - ) -> None: - self.router.add_api_route( - path, - endpoint=endpoint, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=methods, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def frontend( - self, - path: Annotated[ - str, - Doc( - """ - The URL path prefix where the frontend build should be served. - """ - ), - ], - *, - directory: Annotated[ - str | os.PathLike[str], - Doc( - """ - The directory containing the static frontend build output. - """ - ), - ], - fallback: Annotated[ - Literal["auto", "index.html", "404.html"] | None, - Doc( - """ - The fallback file behavior for missing frontend paths. - """ - ), - ] = "auto", - check_dir: Annotated[ - bool, - Doc( - """ - Check that the frontend directory exists when the app is created. - """ - ), - ] = True, - ) -> None: - """ - Serve a static frontend build as low-priority routes. - - Use this for frontend tools that build static files into a directory, - such as `dist`. **FastAPI** path operations are checked first, and - the frontend files are checked only if no normal route matched. - - A typical project could look like this: - - ```text - . - ├── pyproject.toml - ├── app - │ ├── __init__.py - │ └── main.py - └── dist - ├── index.html - └── assets - └── app.js - ``` - - Then in `app/main.py`: - - ```python - from fastapi import FastAPI - - app = FastAPI() - app.frontend("/", directory="dist") - ``` - """ - self.router.frontend( - path, - directory=directory, - fallback=fallback, - check_dir=check_dir, - ) - - def api_route( - self, - path: str, - *, - response_model: Any = Default(None), - status_code: int | None = None, - tags: list[str | Enum] | None = None, - dependencies: Sequence[Depends] | None = None, - summary: str | None = None, - description: str | None = None, - response_description: str = "Successful Response", - responses: dict[int | str, dict[str, Any]] | None = None, - deprecated: bool | None = None, - methods: list[str] | None = None, - operation_id: str | None = None, - response_model_include: IncEx | None = None, - response_model_exclude: IncEx | None = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: type[Response] = Default(JSONResponse), - name: str | None = None, - openapi_extra: dict[str, Any] | None = None, - generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( - generate_unique_id - ), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.router.add_api_route( - path, - func, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=methods, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - return func - - return decorator - - def add_api_websocket_route( - self, - path: str, - endpoint: Callable[..., Any], - name: str | None = None, - *, - dependencies: Sequence[Depends] | None = None, - ) -> None: - self.router.add_api_websocket_route( - path, - endpoint, - name=name, - dependencies=dependencies, - ) - - def websocket( - self, - path: Annotated[ - str, - Doc( - """ - WebSocket path. - """ - ), - ], - name: Annotated[ - str | None, - Doc( - """ - A name for the WebSocket. Only used internally. - """ - ), - ] = None, - *, - dependencies: Annotated[ - Sequence[Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be used for this - WebSocket. - - Read more about it in the - [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/). - """ - ), - ] = None, - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Decorate a WebSocket function. - - Read more about it in the - [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/). - - **Example** - - ```python - from fastapi import FastAPI, WebSocket - - app = FastAPI() - - @app.websocket("/ws") - async def websocket_endpoint(websocket: WebSocket): - await websocket.accept() - while True: - data = await websocket.receive_text() - await websocket.send_text(f"Message text was: {data}") - ``` - """ - - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.add_api_websocket_route( - path, - func, - name=name, - dependencies=dependencies, - ) - return func - - return decorator - - def include_router( - self, - router: Annotated[routing.APIRouter, Doc("The `APIRouter` to include.")], - *, - prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "", - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to all the *path operations* in this - router. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to all the - *path operations* in this router. - - Read more about it in the - [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). - - **Example** - - ```python - from fastapi import Depends, FastAPI - - from .dependencies import get_token_header - from .internal import admin - - app = FastAPI() - - app.include_router( - admin.router, - dependencies=[Depends(get_token_header)], - ) - ``` - """ - ), - ] = None, - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses to be shown in OpenAPI. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/). - - And in the - [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark all the *path operations* in this router as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - **Example** - - ```python - from fastapi import FastAPI - - from .internal import old_api - - app = FastAPI() - - app.include_router( - old_api.router, - deprecated=True, - ) - ``` - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include (or not) all the *path operations* in this router in the - generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - **Example** - - ```python - from fastapi import FastAPI - - from .internal import old_api - - app = FastAPI() - - app.include_router( - old_api.router, - include_in_schema=False, - ) - ``` - """ - ), - ] = True, - default_response_class: Annotated[ - type[Response], - Doc( - """ - Default response class to be used for the *path operations* in this - router. - - Read more in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class). - - **Example** - - ```python - from fastapi import FastAPI - from fastapi.responses import ORJSONResponse - - from .internal import old_api - - app = FastAPI() - - app.include_router( - old_api.router, - default_response_class=ORJSONResponse, - ) - ``` - """ - ), - ] = Default(JSONResponse), - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> None: - """ - Include an `APIRouter` in the same app. - - Read more about it in the - [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/). - - ## Example - - ```python - from fastapi import FastAPI - - from .users import users_router - - app = FastAPI() - - app.include_router(users_router) - ``` - """ - self.router.include_router( - router, - prefix=prefix, - tags=tags, - dependencies=dependencies, - responses=responses, - deprecated=deprecated, - include_in_schema=include_in_schema, - default_response_class=default_response_class, - callbacks=callbacks, - generate_unique_id_function=generate_unique_id_function, - ) - - def get( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - int | None, - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - str | None, - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - str | None, - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - str | None, - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP GET operation. - - ## Example - - ```python - from fastapi import FastAPI - - app = FastAPI() - - @app.get("/items/") - def read_items(): - return [{"name": "Empanada"}, {"name": "Arepa"}] - ``` - """ - return self.router.get( - path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def put( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - int | None, - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - str | None, - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - str | None, - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - str | None, - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP PUT operation. - - ## Example - - ```python - from fastapi import FastAPI - from pydantic import BaseModel - - class Item(BaseModel): - name: str - description: str | None = None - - app = FastAPI() - - @app.put("/items/{item_id}") - def replace_item(item_id: str, item: Item): - return {"message": "Item replaced", "id": item_id} - ``` - """ - return self.router.put( - path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def post( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - int | None, - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - str | None, - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - str | None, - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - str | None, - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP POST operation. - - ## Example - - ```python - from fastapi import FastAPI - from pydantic import BaseModel - - class Item(BaseModel): - name: str - description: str | None = None - - app = FastAPI() - - @app.post("/items/") - def create_item(item: Item): - return {"message": "Item created"} - ``` - """ - return self.router.post( - path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def delete( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - int | None, - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - str | None, - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - str | None, - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - str | None, - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP DELETE operation. - - ## Example - - ```python - from fastapi import FastAPI - - app = FastAPI() - - @app.delete("/items/{item_id}") - def delete_item(item_id: str): - return {"message": "Item deleted"} - ``` - """ - return self.router.delete( - path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def options( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - int | None, - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - str | None, - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - str | None, - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - str | None, - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP OPTIONS operation. - - ## Example - - ```python - from fastapi import FastAPI - - app = FastAPI() - - @app.options("/items/") - def get_item_options(): - return {"additions": ["Aji", "Guacamole"]} - ``` - """ - return self.router.options( - path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def head( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - int | None, - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - str | None, - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - str | None, - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - str | None, - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP HEAD operation. - - ## Example - - ```python - from fastapi import FastAPI, Response - - app = FastAPI() - - @app.head("/items/", status_code=204) - def get_items_headers(response: Response): - response.headers["X-Cat-Dog"] = "Alone in the world" - ``` - """ - return self.router.head( - path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def patch( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - int | None, - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - str | None, - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - str | None, - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - str | None, - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP PATCH operation. - - ## Example - - ```python - from fastapi import FastAPI - from pydantic import BaseModel - - class Item(BaseModel): - name: str - description: str | None = None - - app = FastAPI() - - @app.patch("/items/") - def update_item(item: Item): - return {"message": "Item updated in place"} - ``` - """ - return self.router.patch( - path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def trace( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - int | None, - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - str | None, - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - str | None, - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - str | None, - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP TRACE operation. - - ## Example - - ```python - from fastapi import FastAPI - - app = FastAPI() - - @app.trace("/items/{item_id}") - def trace_item(item_id: str): - return None - ``` - """ - return self.router.trace( - path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def websocket_route( - self, path: str, name: str | None = None - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.router.add_websocket_route(path, func, name=name) - return func - - return decorator - - @deprecated( - """ - on_event is deprecated, use lifespan event handlers instead. - - Read more about it in the - [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/). - """ - ) - def on_event( - self, - event_type: Annotated[ - str, - Doc( - """ - The type of event. `startup` or `shutdown`. - """ - ), - ], - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add an event handler for the application. - - `on_event` is deprecated, use `lifespan` event handlers instead. - - Read more about it in the - [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/#alternative-events-deprecated). - """ - return self.router.on_event(event_type) # ty: ignore[deprecated] - - def middleware( - self, - middleware_type: Annotated[ - str, - Doc( - """ - The type of middleware. Currently only supports `http`. - """ - ), - ], - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a middleware to the application. - - Read more about it in the - [FastAPI docs for Middleware](https://fastapi.tiangolo.com/tutorial/middleware/). - - ## Example - - ```python - import time - from typing import Awaitable, Callable - - from fastapi import FastAPI, Request, Response - - app = FastAPI() - - - @app.middleware("http") - async def add_process_time_header( - request: Request, call_next: Callable[[Request], Awaitable[Response]] - ) -> Response: - start_time = time.time() - response = await call_next(request) - process_time = time.time() - start_time - response.headers["X-Process-Time"] = str(process_time) - return response - ``` - """ - - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.add_middleware(BaseHTTPMiddleware, dispatch=func) - return func - - return decorator - - def exception_handler( - self, - exc_class_or_status_code: Annotated[ - int | type[Exception], - Doc( - """ - The Exception class this would handle, or a status code. - """ - ), - ], - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add an exception handler to the app. - - Read more about it in the - [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/). - - ## Example - - ```python - from fastapi import FastAPI, Request - from fastapi.responses import JSONResponse - - - class UnicornException(Exception): - def __init__(self, name: str): - self.name = name - - - app = FastAPI() - - - @app.exception_handler(UnicornException) - async def unicorn_exception_handler(request: Request, exc: UnicornException): - return JSONResponse( - status_code=418, - content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."}, - ) - ``` - """ - - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.add_exception_handler(exc_class_or_status_code, func) - return func - - return decorator diff --git a/server/venv/Lib/site-packages/fastapi/background.py b/server/venv/Lib/site-packages/fastapi/background.py deleted file mode 100644 index 7677058..0000000 --- a/server/venv/Lib/site-packages/fastapi/background.py +++ /dev/null @@ -1,61 +0,0 @@ -from collections.abc import Callable -from typing import Annotated, Any - -from annotated_doc import Doc -from starlette.background import BackgroundTasks as StarletteBackgroundTasks -from typing_extensions import ParamSpec - -P = ParamSpec("P") - - -class BackgroundTasks(StarletteBackgroundTasks): - """ - A collection of background tasks that will be called after a response has been - sent to the client. - - Read more about it in the - [FastAPI docs for Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/). - - ## Example - - ```python - from fastapi import BackgroundTasks, FastAPI - - app = FastAPI() - - - def write_notification(email: str, message=""): - with open("log.txt", mode="w") as email_file: - content = f"notification for {email}: {message}" - email_file.write(content) - - - @app.post("/send-notification/{email}") - async def send_notification(email: str, background_tasks: BackgroundTasks): - background_tasks.add_task(write_notification, email, message="some notification") - return {"message": "Notification sent in the background"} - ``` - """ - - def add_task( - self, - func: Annotated[ - Callable[P, Any], - Doc( - """ - The function to call after the response is sent. - - It can be a regular `def` function or an `async def` function. - """ - ), - ], - *args: P.args, - **kwargs: P.kwargs, - ) -> None: - """ - Add a function to be called in the background after the response is sent. - - Read more about it in the - [FastAPI docs for Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/). - """ - return super().add_task(func, *args, **kwargs) diff --git a/server/venv/Lib/site-packages/fastapi/cli.py b/server/venv/Lib/site-packages/fastapi/cli.py deleted file mode 100644 index 8d3301e..0000000 --- a/server/venv/Lib/site-packages/fastapi/cli.py +++ /dev/null @@ -1,13 +0,0 @@ -try: - from fastapi_cli.cli import main as cli_main - -except ImportError: # pragma: no cover - cli_main = None # type: ignore - - -def main() -> None: - if not cli_main: # type: ignore[truthy-function] - message = 'To use the fastapi command, please install "fastapi[standard]":\n\n\tpip install "fastapi[standard]"\n' - print(message) - raise RuntimeError(message) # noqa: B904 - cli_main() diff --git a/server/venv/Lib/site-packages/fastapi/concurrency.py b/server/venv/Lib/site-packages/fastapi/concurrency.py deleted file mode 100644 index 76a5a2e..0000000 --- a/server/venv/Lib/site-packages/fastapi/concurrency.py +++ /dev/null @@ -1,41 +0,0 @@ -from collections.abc import AsyncGenerator -from contextlib import AbstractContextManager -from contextlib import asynccontextmanager as asynccontextmanager -from typing import TypeVar - -import anyio.to_thread -from anyio import CapacityLimiter -from starlette.concurrency import iterate_in_threadpool as iterate_in_threadpool # noqa -from starlette.concurrency import run_in_threadpool as run_in_threadpool # noqa -from starlette.concurrency import ( # noqa - run_until_first_complete as run_until_first_complete, -) - -_T = TypeVar("_T") - - -@asynccontextmanager -async def contextmanager_in_threadpool( - cm: AbstractContextManager[_T], -) -> AsyncGenerator[_T, None]: - # blocking __exit__ from running waiting on a free thread - # can create race conditions/deadlocks if the context manager itself - # has its own internal pool (e.g. a database connection pool) - # to avoid this we let __exit__ run without a capacity limit - # since we're creating a new limiter for each call, any non-zero limit - # works (1 is arbitrary) - exit_limiter = CapacityLimiter(1) - try: - yield await run_in_threadpool(cm.__enter__) - except Exception as e: - ok = bool( - await anyio.to_thread.run_sync( - cm.__exit__, type(e), e, e.__traceback__, limiter=exit_limiter - ) - ) - if not ok: - raise e - else: - await anyio.to_thread.run_sync( - cm.__exit__, None, None, None, limiter=exit_limiter - ) diff --git a/server/venv/Lib/site-packages/fastapi/datastructures.py b/server/venv/Lib/site-packages/fastapi/datastructures.py deleted file mode 100644 index 1da784c..0000000 --- a/server/venv/Lib/site-packages/fastapi/datastructures.py +++ /dev/null @@ -1,186 +0,0 @@ -from collections.abc import Callable, Mapping -from typing import ( - Annotated, - Any, - BinaryIO, - TypeVar, - cast, -) - -from annotated_doc import Doc -from pydantic import GetJsonSchemaHandler -from starlette.datastructures import URL as URL # noqa: F401 -from starlette.datastructures import Address as Address # noqa: F401 -from starlette.datastructures import FormData as FormData # noqa: F401 -from starlette.datastructures import Headers as Headers # noqa: F401 -from starlette.datastructures import QueryParams as QueryParams # noqa: F401 -from starlette.datastructures import State as State # noqa: F401 -from starlette.datastructures import UploadFile as StarletteUploadFile - - -class UploadFile(StarletteUploadFile): - """ - A file uploaded in a request. - - Define it as a *path operation function* (or dependency) parameter. - - If you are using a regular `def` function, you can use the `upload_file.file` - attribute to access the raw standard Python file (blocking, not async), useful and - needed for non-async code. - - Read more about it in the - [FastAPI docs for Request Files](https://fastapi.tiangolo.com/tutorial/request-files/). - - ## Example - - ```python - from typing import Annotated - - from fastapi import FastAPI, File, UploadFile - - app = FastAPI() - - - @app.post("/files/") - async def create_file(file: Annotated[bytes, File()]): - return {"file_size": len(file)} - - - @app.post("/uploadfile/") - async def create_upload_file(file: UploadFile): - return {"filename": file.filename} - ``` - """ - - file: Annotated[ - BinaryIO, - Doc("The standard Python file object (non-async)."), - ] - filename: Annotated[str | None, Doc("The original file name.")] - size: Annotated[int | None, Doc("The size of the file in bytes.")] - headers: Annotated[Headers, Doc("The headers of the request.")] - content_type: Annotated[ - str | None, Doc("The content type of the request, from the headers.") - ] - - async def write( - self, - data: Annotated[ - bytes, - Doc( - """ - The bytes to write to the file. - """ - ), - ], - ) -> None: - """ - Write some bytes to the file. - - You normally wouldn't use this from a file you read in a request. - - To be awaitable, compatible with async, this is run in threadpool. - """ - return await super().write(data) - - async def read( - self, - size: Annotated[ - int, - Doc( - """ - The number of bytes to read from the file. - """ - ), - ] = -1, - ) -> bytes: - """ - Read some bytes from the file. - - To be awaitable, compatible with async, this is run in threadpool. - """ - return await super().read(size) - - async def seek( - self, - offset: Annotated[ - int, - Doc( - """ - The position in bytes to seek to in the file. - """ - ), - ], - ) -> None: - """ - Move to a position in the file. - - Any next read or write will be done from that position. - - To be awaitable, compatible with async, this is run in threadpool. - """ - return await super().seek(offset) - - async def close(self) -> None: - """ - Close the file. - - To be awaitable, compatible with async, this is run in threadpool. - """ - return await super().close() - - @classmethod - def _validate(cls, __input_value: Any, _: Any) -> "UploadFile": - if not isinstance(__input_value, StarletteUploadFile): - raise ValueError(f"Expected UploadFile, received: {type(__input_value)}") - return cast(UploadFile, __input_value) - - @classmethod - def __get_pydantic_json_schema__( - cls, core_schema: Mapping[str, Any], handler: GetJsonSchemaHandler - ) -> dict[str, Any]: - return {"type": "string", "contentMediaType": "application/octet-stream"} - - @classmethod - def __get_pydantic_core_schema__( - cls, source: type[Any], handler: Callable[[Any], Mapping[str, Any]] - ) -> Mapping[str, Any]: - from ._compat.v2 import with_info_plain_validator_function - - return with_info_plain_validator_function(cls._validate) - - -class DefaultPlaceholder: - """ - You shouldn't use this class directly. - - It's used internally to recognize when a default value has been overwritten, even - if the overridden default value was truthy. - """ - - def __init__(self, value: Any): - self.value = value - - def __bool__(self) -> bool: - return bool(self.value) - - def __eq__(self, o: object) -> bool: - return isinstance(o, DefaultPlaceholder) and o.value == self.value - - -DefaultType = TypeVar("DefaultType") - - -def Default(value: DefaultType) -> DefaultType: - """ - You shouldn't use this function directly. - - It's used internally to recognize when a default value has been overwritten, even - if the overridden default value was truthy. - """ - return DefaultPlaceholder(value) # type: ignore - - -# Sentinel for "parameter not provided" in Param/FieldInfo. -# Typed as None to satisfy ty -_Unset = Default(None) diff --git a/server/venv/Lib/site-packages/fastapi/dependencies/__init__.py b/server/venv/Lib/site-packages/fastapi/dependencies/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/venv/Lib/site-packages/fastapi/dependencies/models.py b/server/venv/Lib/site-packages/fastapi/dependencies/models.py deleted file mode 100644 index 25ffb0d..0000000 --- a/server/venv/Lib/site-packages/fastapi/dependencies/models.py +++ /dev/null @@ -1,193 +0,0 @@ -import inspect -import sys -from collections.abc import Callable -from dataclasses import dataclass, field -from functools import cached_property, partial -from typing import Any, Literal - -from fastapi._compat import ModelField -from fastapi.security.base import SecurityBase -from fastapi.types import DependencyCacheKey - -if sys.version_info >= (3, 13): # pragma: no cover - from inspect import iscoroutinefunction -else: # pragma: no cover - from asyncio import iscoroutinefunction - - -def _unwrapped_call(call: Callable[..., Any] | None) -> Any: - if call is None: - return call # pragma: no cover - unwrapped = inspect.unwrap(_impartial(call)) - return unwrapped - - -def _impartial(func: Callable[..., Any]) -> Callable[..., Any]: - while isinstance(func, partial): - func = func.func - return func - - -@dataclass -class Dependant: - path_params: list[ModelField] = field(default_factory=list) - query_params: list[ModelField] = field(default_factory=list) - header_params: list[ModelField] = field(default_factory=list) - cookie_params: list[ModelField] = field(default_factory=list) - body_params: list[ModelField] = field(default_factory=list) - dependencies: list["Dependant"] = field(default_factory=list) - name: str | None = None - call: Callable[..., Any] | None = None - request_param_name: str | None = None - websocket_param_name: str | None = None - http_connection_param_name: str | None = None - response_param_name: str | None = None - background_tasks_param_name: str | None = None - security_scopes_param_name: str | None = None - own_oauth_scopes: list[str] | None = None - parent_oauth_scopes: list[str] | None = None - use_cache: bool = True - path: str | None = None - scope: Literal["function", "request"] | None = None - - @cached_property - def oauth_scopes(self) -> list[str]: - scopes = self.parent_oauth_scopes.copy() if self.parent_oauth_scopes else [] - # This doesn't use a set to preserve order, just in case - for scope in self.own_oauth_scopes or []: - if scope not in scopes: - scopes.append(scope) - return scopes - - @cached_property - def cache_key(self) -> DependencyCacheKey: - scopes_for_cache = ( - tuple(sorted(set(self.oauth_scopes or []))) if self._uses_scopes else () - ) - return ( - self.call, - scopes_for_cache, - self.computed_scope or "", - ) - - @cached_property - def _uses_scopes(self) -> bool: - if self.own_oauth_scopes: - return True - if self.security_scopes_param_name is not None: - return True - if self._is_security_scheme: - return True - for sub_dep in self.dependencies: - if sub_dep._uses_scopes: - return True - return False - - @cached_property - def _is_security_scheme(self) -> bool: - if self.call is None: - return False # pragma: no cover - unwrapped = _unwrapped_call(self.call) - return isinstance(unwrapped, SecurityBase) - - # Mainly to get the type of SecurityBase, but it's the same self.call - @cached_property - def _security_scheme(self) -> SecurityBase: - unwrapped = _unwrapped_call(self.call) - assert isinstance(unwrapped, SecurityBase) - return unwrapped - - @cached_property - def _security_dependencies(self) -> list["Dependant"]: - security_deps = [dep for dep in self.dependencies if dep._is_security_scheme] - return security_deps - - @cached_property - def is_gen_callable(self) -> bool: - if self.call is None: - return False # pragma: no cover - if inspect.isgeneratorfunction( - _impartial(self.call) - ) or inspect.isgeneratorfunction(_unwrapped_call(self.call)): - return True - if inspect.isclass(_unwrapped_call(self.call)): - return False - dunder_call = getattr(_impartial(self.call), "__call__", None) # noqa: B004 - if dunder_call is None: - return False # pragma: no cover - if inspect.isgeneratorfunction( - _impartial(dunder_call) - ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_call)): - return True - dunder_unwrapped_call = getattr(_unwrapped_call(self.call), "__call__", None) # noqa: B004 - if dunder_unwrapped_call is None: - return False # pragma: no cover - if inspect.isgeneratorfunction( - _impartial(dunder_unwrapped_call) - ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_unwrapped_call)): - return True - return False - - @cached_property - def is_async_gen_callable(self) -> bool: - if self.call is None: - return False # pragma: no cover - if inspect.isasyncgenfunction( - _impartial(self.call) - ) or inspect.isasyncgenfunction(_unwrapped_call(self.call)): - return True - if inspect.isclass(_unwrapped_call(self.call)): - return False - dunder_call = getattr(_impartial(self.call), "__call__", None) # noqa: B004 - if dunder_call is None: - return False # pragma: no cover - if inspect.isasyncgenfunction( - _impartial(dunder_call) - ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_call)): - return True - dunder_unwrapped_call = getattr(_unwrapped_call(self.call), "__call__", None) # noqa: B004 - if dunder_unwrapped_call is None: - return False # pragma: no cover - if inspect.isasyncgenfunction( - _impartial(dunder_unwrapped_call) - ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_unwrapped_call)): - return True - return False - - @cached_property - def is_coroutine_callable(self) -> bool: - if self.call is None: - return False # pragma: no cover - if inspect.isroutine(_impartial(self.call)) and iscoroutinefunction( - _impartial(self.call) - ): - return True - if inspect.isroutine(_unwrapped_call(self.call)) and iscoroutinefunction( - _unwrapped_call(self.call) - ): - return True - if inspect.isclass(_unwrapped_call(self.call)): - return False - dunder_call = getattr(_impartial(self.call), "__call__", None) # noqa: B004 - if dunder_call is None: - return False # pragma: no cover - if iscoroutinefunction(_impartial(dunder_call)) or iscoroutinefunction( - _unwrapped_call(dunder_call) - ): - return True - dunder_unwrapped_call = getattr(_unwrapped_call(self.call), "__call__", None) # noqa: B004 - if dunder_unwrapped_call is None: - return False # pragma: no cover - if iscoroutinefunction( - _impartial(dunder_unwrapped_call) - ) or iscoroutinefunction(_unwrapped_call(dunder_unwrapped_call)): - return True - return False - - @cached_property - def computed_scope(self) -> str | None: - if self.scope: - return self.scope - if self.is_gen_callable or self.is_async_gen_callable: - return "request" - return None diff --git a/server/venv/Lib/site-packages/fastapi/dependencies/utils.py b/server/venv/Lib/site-packages/fastapi/dependencies/utils.py deleted file mode 100644 index 40dffba..0000000 --- a/server/venv/Lib/site-packages/fastapi/dependencies/utils.py +++ /dev/null @@ -1,1061 +0,0 @@ -import dataclasses -import inspect -import sys -from collections.abc import ( - AsyncGenerator, - AsyncIterable, - AsyncIterator, - Callable, - Generator, - Iterable, - Iterator, - Mapping, - Sequence, -) -from contextlib import AsyncExitStack, contextmanager -from copy import copy, deepcopy -from dataclasses import dataclass -from typing import ( - Annotated, - Any, - ForwardRef, - Literal, - Union, - cast, - get_args, - get_origin, -) - -from fastapi import params -from fastapi._compat import ( - ModelField, - RequiredParam, - Undefined, - copy_field_info, - create_body_model, - evaluate_forwardref, - field_annotation_is_scalar, - field_annotation_is_scalar_sequence, - field_annotation_is_sequence, - get_cached_model_fields, - get_missing_field_error, - is_bytes_or_nonable_bytes_annotation, - is_bytes_sequence_annotation, - is_scalar_field, - is_uploadfile_or_nonable_uploadfile_annotation, - is_uploadfile_sequence_annotation, - lenient_issubclass, - sequence_types, - serialize_sequence_value, - value_is_sequence, -) -from fastapi.background import BackgroundTasks -from fastapi.concurrency import ( - asynccontextmanager, - contextmanager_in_threadpool, -) -from fastapi.dependencies.models import Dependant -from fastapi.exceptions import DependencyScopeError -from fastapi.logger import logger -from fastapi.security.oauth2 import SecurityScopes -from fastapi.types import DependencyCacheKey -from fastapi.utils import create_model_field, get_path_param_names -from pydantic import BaseModel, Json -from pydantic.fields import FieldInfo -from starlette.background import BackgroundTasks as StarletteBackgroundTasks -from starlette.concurrency import run_in_threadpool -from starlette.datastructures import ( - FormData, - Headers, - ImmutableMultiDict, - QueryParams, - UploadFile, -) -from starlette.requests import HTTPConnection, Request -from starlette.responses import Response -from starlette.websockets import WebSocket -from typing_inspection.typing_objects import is_typealiastype - -multipart_not_installed_error = ( - 'Form data requires "python-multipart" to be installed. \n' - 'You can install "python-multipart" with: \n\n' - "pip install python-multipart\n" -) -multipart_incorrect_install_error = ( - 'Form data requires "python-multipart" to be installed. ' - 'It seems you installed "multipart" instead. \n' - 'You can remove "multipart" with: \n\n' - "pip uninstall multipart\n\n" - 'And then install "python-multipart" with: \n\n' - "pip install python-multipart\n" -) - - -def ensure_multipart_is_installed() -> None: - try: - from python_multipart import __version__ - - # Import an attribute that can be mocked/deleted in testing - assert __version__ > "0.0.12" - except (ImportError, AssertionError): - try: - # __version__ is available in both multiparts, and can be mocked - from multipart import ( # type: ignore[no-redef,import-untyped] - __version__, - ) - - assert __version__ - try: - # parse_options_header is only available in the right multipart - from multipart.multipart import ( # type: ignore[import-untyped] - parse_options_header, - ) - - assert parse_options_header - except ImportError: - logger.error(multipart_incorrect_install_error) - raise RuntimeError(multipart_incorrect_install_error) from None - except ImportError: - logger.error(multipart_not_installed_error) - raise RuntimeError(multipart_not_installed_error) from None - - -def get_parameterless_sub_dependant(*, depends: params.Depends, path: str) -> Dependant: - assert callable(depends.dependency), ( - "A parameter-less dependency must have a callable dependency" - ) - own_oauth_scopes: list[str] = [] - if isinstance(depends, params.Security) and depends.scopes: - own_oauth_scopes.extend(depends.scopes) - return get_dependant( - path=path, - call=depends.dependency, - scope=depends.scope, - own_oauth_scopes=own_oauth_scopes, - ) - - -def get_flat_dependant( - dependant: Dependant, - *, - skip_repeats: bool = False, - visited: list[DependencyCacheKey] | None = None, - parent_oauth_scopes: list[str] | None = None, -) -> Dependant: - if visited is None: - visited = [] - visited.append(dependant.cache_key) - use_parent_oauth_scopes = (parent_oauth_scopes or []) + ( - dependant.oauth_scopes or [] - ) - - flat_dependant = Dependant( - path_params=dependant.path_params.copy(), - query_params=dependant.query_params.copy(), - header_params=dependant.header_params.copy(), - cookie_params=dependant.cookie_params.copy(), - body_params=dependant.body_params.copy(), - name=dependant.name, - call=dependant.call, - request_param_name=dependant.request_param_name, - websocket_param_name=dependant.websocket_param_name, - http_connection_param_name=dependant.http_connection_param_name, - response_param_name=dependant.response_param_name, - background_tasks_param_name=dependant.background_tasks_param_name, - security_scopes_param_name=dependant.security_scopes_param_name, - own_oauth_scopes=dependant.own_oauth_scopes, - parent_oauth_scopes=use_parent_oauth_scopes, - use_cache=dependant.use_cache, - path=dependant.path, - scope=dependant.scope, - ) - for sub_dependant in dependant.dependencies: - if skip_repeats and sub_dependant.cache_key in visited: - continue - flat_sub = get_flat_dependant( - sub_dependant, - skip_repeats=skip_repeats, - visited=visited, - parent_oauth_scopes=flat_dependant.oauth_scopes, - ) - flat_dependant.dependencies.append(flat_sub) - flat_dependant.path_params.extend(flat_sub.path_params) - flat_dependant.query_params.extend(flat_sub.query_params) - flat_dependant.header_params.extend(flat_sub.header_params) - flat_dependant.cookie_params.extend(flat_sub.cookie_params) - flat_dependant.body_params.extend(flat_sub.body_params) - flat_dependant.dependencies.extend(flat_sub.dependencies) - - return flat_dependant - - -def _get_flat_fields_from_params(fields: list[ModelField]) -> list[ModelField]: - if not fields: - return fields - first_field = fields[0] - if len(fields) == 1 and lenient_issubclass( - first_field.field_info.annotation, BaseModel - ): - fields_to_extract = get_cached_model_fields(first_field.field_info.annotation) - return fields_to_extract - return fields - - -def get_flat_params(dependant: Dependant) -> list[ModelField]: - flat_dependant = get_flat_dependant(dependant, skip_repeats=True) - path_params = _get_flat_fields_from_params(flat_dependant.path_params) - query_params = _get_flat_fields_from_params(flat_dependant.query_params) - header_params = _get_flat_fields_from_params(flat_dependant.header_params) - cookie_params = _get_flat_fields_from_params(flat_dependant.cookie_params) - return path_params + query_params + header_params + cookie_params - - -def _get_signature(call: Callable[..., Any]) -> inspect.Signature: - try: - signature = inspect.signature(call, eval_str=True) - except NameError: - # Handle type annotations with if TYPE_CHECKING, not used by FastAPI - # e.g. dependency return types - if sys.version_info >= (3, 14): - from annotationlib import Format - - signature = inspect.signature(call, annotation_format=Format.FORWARDREF) - else: - signature = inspect.signature(call) - return signature - - -def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature: - signature = _get_signature(call) - unwrapped = inspect.unwrap(call) - globalns = getattr(unwrapped, "__globals__", {}) - typed_params = [ - inspect.Parameter( - name=param.name, - kind=param.kind, - default=param.default, - annotation=get_typed_annotation(param.annotation, globalns), - ) - for param in signature.parameters.values() - ] - typed_signature = inspect.Signature(typed_params) - return typed_signature - - -def get_typed_annotation(annotation: Any, globalns: dict[str, Any]) -> Any: - if isinstance(annotation, str): - annotation = ForwardRef(annotation) - annotation = evaluate_forwardref(annotation, globalns, globalns) - if annotation is type(None): - return None - return annotation - - -def get_typed_return_annotation(call: Callable[..., Any]) -> Any: - signature = _get_signature(call) - unwrapped = inspect.unwrap(call) - annotation = signature.return_annotation - - if annotation is inspect.Signature.empty: - return None - - globalns = getattr(unwrapped, "__globals__", {}) - return get_typed_annotation(annotation, globalns) - - -_STREAM_ORIGINS = { - AsyncIterable, - AsyncIterator, - AsyncGenerator, - Iterable, - Iterator, - Generator, -} - - -def get_stream_item_type(annotation: Any) -> Any | None: - origin = get_origin(annotation) - if origin is not None and origin in _STREAM_ORIGINS: - type_args = get_args(annotation) - if type_args: - return type_args[0] - return Any - return None - - -def get_dependant( - *, - path: str, - call: Callable[..., Any], - name: str | None = None, - own_oauth_scopes: list[str] | None = None, - parent_oauth_scopes: list[str] | None = None, - use_cache: bool = True, - scope: Literal["function", "request"] | None = None, -) -> Dependant: - dependant = Dependant( - call=call, - name=name, - path=path, - use_cache=use_cache, - scope=scope, - own_oauth_scopes=own_oauth_scopes, - parent_oauth_scopes=parent_oauth_scopes, - ) - current_scopes = (parent_oauth_scopes or []) + (own_oauth_scopes or []) - path_param_names = get_path_param_names(path) - endpoint_signature = get_typed_signature(call) - signature_params = endpoint_signature.parameters - for param_name, param in signature_params.items(): - is_path_param = param_name in path_param_names - param_details = analyze_param( - param_name=param_name, - annotation=param.annotation, - value=param.default, - is_path_param=is_path_param, - ) - if param_details.depends is not None: - assert param_details.depends.dependency - if ( - (dependant.is_gen_callable or dependant.is_async_gen_callable) - and dependant.computed_scope == "request" - and param_details.depends.scope == "function" - ): - assert dependant.call - call_name = getattr(dependant.call, "__name__", "") - raise DependencyScopeError( - f'The dependency "{call_name}" has a scope of ' - '"request", it cannot depend on dependencies with scope "function".' - ) - sub_own_oauth_scopes: list[str] = [] - if isinstance(param_details.depends, params.Security): - if param_details.depends.scopes: - sub_own_oauth_scopes = list(param_details.depends.scopes) - sub_dependant = get_dependant( - path=path, - call=param_details.depends.dependency, - name=param_name, - own_oauth_scopes=sub_own_oauth_scopes, - parent_oauth_scopes=current_scopes, - use_cache=param_details.depends.use_cache, - scope=param_details.depends.scope, - ) - dependant.dependencies.append(sub_dependant) - continue - if add_non_field_param_to_dependency( - param_name=param_name, - type_annotation=param_details.type_annotation, - dependant=dependant, - ): - assert param_details.field is None, ( - f"Cannot specify multiple FastAPI annotations for {param_name!r}" - ) - continue - assert param_details.field is not None - if isinstance(param_details.field.field_info, params.Body): - dependant.body_params.append(param_details.field) - else: - add_param_to_fields(field=param_details.field, dependant=dependant) - return dependant - - -def add_non_field_param_to_dependency( - *, param_name: str, type_annotation: Any, dependant: Dependant -) -> bool | None: - if lenient_issubclass(type_annotation, Request): - dependant.request_param_name = param_name - return True - elif lenient_issubclass(type_annotation, WebSocket): - dependant.websocket_param_name = param_name - return True - elif lenient_issubclass(type_annotation, HTTPConnection): - dependant.http_connection_param_name = param_name - return True - elif lenient_issubclass(type_annotation, Response): - dependant.response_param_name = param_name - return True - elif lenient_issubclass(type_annotation, StarletteBackgroundTasks): - dependant.background_tasks_param_name = param_name - return True - elif lenient_issubclass(type_annotation, SecurityScopes): - dependant.security_scopes_param_name = param_name - return True - return None - - -@dataclass -class ParamDetails: - type_annotation: Any - depends: params.Depends | None - field: ModelField | None - - -def analyze_param( - *, - param_name: str, - annotation: Any, - value: Any, - is_path_param: bool, -) -> ParamDetails: - field_info = None - depends = None - type_annotation: Any = Any - use_annotation: Any = Any - if is_typealiastype(annotation): - # unpack in case PEP 695 type syntax is used - annotation = annotation.__value__ - if annotation is not inspect.Signature.empty: - use_annotation = annotation - type_annotation = annotation - # Extract Annotated info - if get_origin(use_annotation) is Annotated: - annotated_args = get_args(annotation) - type_annotation = annotated_args[0] - fastapi_annotations = [ - arg - for arg in annotated_args[1:] - if isinstance(arg, (FieldInfo, params.Depends)) - ] - fastapi_specific_annotations = [ - arg - for arg in fastapi_annotations - if isinstance( - arg, - ( - params.Param, - params.Body, - params.Depends, - ), - ) - ] - if fastapi_specific_annotations: - fastapi_annotation: FieldInfo | params.Depends | None = ( - fastapi_specific_annotations[-1] - ) - else: - fastapi_annotation = None - # Set default for Annotated FieldInfo - if isinstance(fastapi_annotation, FieldInfo): - # Copy `field_info` because we mutate `field_info.default` below. - field_info = copy_field_info( - field_info=fastapi_annotation, - annotation=use_annotation, - ) - assert ( - field_info.default == Undefined or field_info.default == RequiredParam - ), ( - f"`{field_info.__class__.__name__}` default value cannot be set in" - f" `Annotated` for {param_name!r}. Set the default value with `=` instead." - ) - if value is not inspect.Signature.empty: - assert not is_path_param, "Path parameters cannot have default values" - field_info.default = value - else: - field_info.default = RequiredParam - # Get Annotated Depends - elif isinstance(fastapi_annotation, params.Depends): - depends = fastapi_annotation - # Get Depends from default value - if isinstance(value, params.Depends): - assert depends is None, ( - "Cannot specify `Depends` in `Annotated` and default value" - f" together for {param_name!r}" - ) - assert field_info is None, ( - "Cannot specify a FastAPI annotation in `Annotated` and `Depends` as a" - f" default value together for {param_name!r}" - ) - depends = value - # Get FieldInfo from default value - elif isinstance(value, FieldInfo): - assert field_info is None, ( - "Cannot specify FastAPI annotations in `Annotated` and default value" - f" together for {param_name!r}" - ) - field_info = value - if isinstance(field_info, FieldInfo): - field_info.annotation = type_annotation - - # Get Depends from type annotation - if depends is not None and depends.dependency is None: - # Copy `depends` before mutating it - depends = copy(depends) - depends = dataclasses.replace(depends, dependency=type_annotation) - - # Handle non-param type annotations like Request - # Only apply special handling when there's no explicit Depends - if there's a Depends, - # the dependency will be called and its return value used instead of the special injection - if depends is None and lenient_issubclass( - type_annotation, - ( - Request, - WebSocket, - HTTPConnection, - Response, - StarletteBackgroundTasks, - SecurityScopes, - ), - ): - assert field_info is None, ( - f"Cannot specify FastAPI annotation for type {type_annotation!r}" - ) - # Handle default assignations, neither field_info nor depends was not found in Annotated nor default value - elif field_info is None and depends is None: - default_value = value if value is not inspect.Signature.empty else RequiredParam - if is_path_param: - # We might check here that `default_value is RequiredParam`, but the fact is that the same - # parameter might sometimes be a path parameter and sometimes not. See - # `tests/test_infer_param_optionality.py` for an example. - field_info = params.Path(annotation=use_annotation) - elif is_uploadfile_or_nonable_uploadfile_annotation( - type_annotation - ) or is_uploadfile_sequence_annotation(type_annotation): - field_info = params.File(annotation=use_annotation, default=default_value) - elif not field_annotation_is_scalar(annotation=type_annotation): - field_info = params.Body(annotation=use_annotation, default=default_value) - else: - field_info = params.Query(annotation=use_annotation, default=default_value) - - field = None - # It's a field_info, not a dependency - if field_info is not None: - # Handle field_info.in_ - if is_path_param: - assert isinstance(field_info, params.Path), ( - f"Cannot use `{field_info.__class__.__name__}` for path param" - f" {param_name!r}" - ) - elif ( - isinstance(field_info, params.Param) - and getattr(field_info, "in_", None) is None - ): - field_info.in_ = params.ParamTypes.query - use_annotation_from_field_info = use_annotation - if isinstance(field_info, params.Form): - ensure_multipart_is_installed() - if not field_info.alias and getattr(field_info, "convert_underscores", None): - alias = param_name.replace("_", "-") - else: - alias = field_info.alias or param_name - field_info.alias = alias - field = create_model_field( - name=param_name, - type_=use_annotation_from_field_info, - default=field_info.default, - alias=alias, - field_info=field_info, - ) - if is_path_param: - assert is_scalar_field(field=field), ( - "Path params must be of one of the supported types" - ) - elif isinstance(field_info, params.Query): - assert ( - is_scalar_field(field) - or field_annotation_is_scalar_sequence(field.field_info.annotation) - or lenient_issubclass(field.field_info.annotation, BaseModel) - ), f"Query parameter {param_name!r} must be one of the supported types" - - return ParamDetails(type_annotation=type_annotation, depends=depends, field=field) - - -def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None: - field_info = field.field_info - field_info_in = getattr(field_info, "in_", None) - if field_info_in == params.ParamTypes.path: - dependant.path_params.append(field) - elif field_info_in == params.ParamTypes.query: - dependant.query_params.append(field) - elif field_info_in == params.ParamTypes.header: - dependant.header_params.append(field) - else: - assert field_info_in == params.ParamTypes.cookie, ( - f"non-body parameters must be in path, query, header or cookie: {field.name}" - ) - dependant.cookie_params.append(field) - - -async def _solve_generator( - *, dependant: Dependant, stack: AsyncExitStack, sub_values: dict[str, Any] -) -> Any: - assert dependant.call - if dependant.is_async_gen_callable: - cm = asynccontextmanager(dependant.call)(**sub_values) - elif dependant.is_gen_callable: - cm = contextmanager_in_threadpool(contextmanager(dependant.call)(**sub_values)) - return await stack.enter_async_context(cm) - - -@dataclass -class SolvedDependency: - values: dict[str, Any] - errors: list[Any] - background_tasks: StarletteBackgroundTasks | None - response: Response - dependency_cache: dict[DependencyCacheKey, Any] - - -async def solve_dependencies( - *, - request: Request | WebSocket, - dependant: Dependant, - body: dict[str, Any] | FormData | bytes | None = None, - background_tasks: StarletteBackgroundTasks | None = None, - response: Response | None = None, - dependency_overrides_provider: Any | None = None, - dependency_cache: dict[DependencyCacheKey, Any] | None = None, - # TODO: remove this parameter later, no longer used, not removing it yet as some - # people might be monkey patching this function (although that's not supported) - async_exit_stack: AsyncExitStack, - embed_body_fields: bool, -) -> SolvedDependency: - request_astack = request.scope.get("fastapi_inner_astack") - assert isinstance(request_astack, AsyncExitStack), ( - "fastapi_inner_astack not found in request scope" - ) - function_astack = request.scope.get("fastapi_function_astack") - assert isinstance(function_astack, AsyncExitStack), ( - "fastapi_function_astack not found in request scope" - ) - values: dict[str, Any] = {} - errors: list[Any] = [] - if response is None: - response = Response() - del response.headers["content-length"] - response.status_code = None # type: ignore - if dependency_cache is None: - dependency_cache = {} - for sub_dependant in dependant.dependencies: - sub_dependant.call = cast(Callable[..., Any], sub_dependant.call) - call = sub_dependant.call - use_sub_dependant = sub_dependant - if ( - dependency_overrides_provider - and dependency_overrides_provider.dependency_overrides - ): - original_call = sub_dependant.call - call = getattr( - dependency_overrides_provider, "dependency_overrides", {} - ).get(original_call, original_call) - use_path: str = sub_dependant.path # type: ignore - use_sub_dependant = get_dependant( - path=use_path, - call=call, - name=sub_dependant.name, - parent_oauth_scopes=sub_dependant.oauth_scopes, - scope=sub_dependant.scope, - ) - - solved_result = await solve_dependencies( - request=request, - dependant=use_sub_dependant, - body=body, - background_tasks=background_tasks, - response=response, - dependency_overrides_provider=dependency_overrides_provider, - dependency_cache=dependency_cache, - async_exit_stack=async_exit_stack, - embed_body_fields=embed_body_fields, - ) - background_tasks = solved_result.background_tasks - if solved_result.errors: - errors.extend(solved_result.errors) - continue - if sub_dependant.use_cache and sub_dependant.cache_key in dependency_cache: - solved = dependency_cache[sub_dependant.cache_key] - elif ( - use_sub_dependant.is_gen_callable or use_sub_dependant.is_async_gen_callable - ): - use_astack = request_astack - if sub_dependant.scope == "function": - use_astack = function_astack - solved = await _solve_generator( - dependant=use_sub_dependant, - stack=use_astack, - sub_values=solved_result.values, - ) - elif use_sub_dependant.is_coroutine_callable: - solved = await call(**solved_result.values) - else: - solved = await run_in_threadpool(call, **solved_result.values) - if sub_dependant.name is not None: - values[sub_dependant.name] = solved - if sub_dependant.cache_key not in dependency_cache: - dependency_cache[sub_dependant.cache_key] = solved - path_values, path_errors = request_params_to_args( - dependant.path_params, request.path_params - ) - query_values, query_errors = request_params_to_args( - dependant.query_params, request.query_params - ) - header_values, header_errors = request_params_to_args( - dependant.header_params, request.headers - ) - cookie_values, cookie_errors = request_params_to_args( - dependant.cookie_params, request.cookies - ) - values.update(path_values) - values.update(query_values) - values.update(header_values) - values.update(cookie_values) - errors += path_errors + query_errors + header_errors + cookie_errors - if dependant.body_params: - ( - body_values, - body_errors, - ) = await request_body_to_args( # body_params checked above - body_fields=dependant.body_params, - received_body=body, - embed_body_fields=embed_body_fields, - ) - values.update(body_values) - errors.extend(body_errors) - if dependant.http_connection_param_name: - values[dependant.http_connection_param_name] = request - if dependant.request_param_name and isinstance(request, Request): - values[dependant.request_param_name] = request - elif dependant.websocket_param_name and isinstance(request, WebSocket): - values[dependant.websocket_param_name] = request - if dependant.background_tasks_param_name: - if background_tasks is None: - background_tasks = BackgroundTasks() - values[dependant.background_tasks_param_name] = background_tasks - if dependant.response_param_name: - values[dependant.response_param_name] = response - if dependant.security_scopes_param_name: - values[dependant.security_scopes_param_name] = SecurityScopes( - scopes=dependant.oauth_scopes - ) - return SolvedDependency( - values=values, - errors=errors, - background_tasks=background_tasks, - response=response, - dependency_cache=dependency_cache, - ) - - -def _validate_value_with_model_field( - *, field: ModelField, value: Any, values: dict[str, Any], loc: tuple[str, ...] -) -> tuple[Any, list[Any]]: - if value is None: - if field.field_info.is_required(): - return None, [get_missing_field_error(loc=loc)] - else: - return deepcopy(field.default), [] - return field.validate(value, values, loc=loc) - - -def _is_json_field(field: ModelField) -> bool: - return any(type(item) is Json for item in field.field_info.metadata) - - -def _get_multidict_value( - field: ModelField, values: Mapping[str, Any], alias: str | None = None -) -> Any: - alias = alias or get_validation_alias(field) - if ( - (not _is_json_field(field)) - and field_annotation_is_sequence(field.field_info.annotation) - and isinstance(values, (ImmutableMultiDict, Headers)) - ): - value = values.getlist(alias) - else: - value = values.get(alias, None) - if ( - value is None - or ( - isinstance(field.field_info, params.Form) - and isinstance(value, str) # For type checks - and value == "" - ) - or ( - field_annotation_is_sequence(field.field_info.annotation) - and len(value) == 0 - ) - ): - if field.field_info.is_required(): - return - else: - return deepcopy(field.default) - return value - - -def request_params_to_args( - fields: Sequence[ModelField], - received_params: Mapping[str, Any] | QueryParams | Headers, -) -> tuple[dict[str, Any], list[Any]]: - values: dict[str, Any] = {} - errors: list[dict[str, Any]] = [] - - if not fields: - return values, errors - - first_field = fields[0] - fields_to_extract = fields - single_not_embedded_field = False - default_convert_underscores = True - if len(fields) == 1 and lenient_issubclass( - first_field.field_info.annotation, BaseModel - ): - fields_to_extract = get_cached_model_fields(first_field.field_info.annotation) - single_not_embedded_field = True - # If headers are in a Pydantic model, the way to disable convert_underscores - # would be with Header(convert_underscores=False) at the Pydantic model level - default_convert_underscores = getattr( - first_field.field_info, "convert_underscores", True - ) - - params_to_process: dict[str, Any] = {} - - processed_keys = set() - - for field in fields_to_extract: - alias = None - if isinstance(received_params, Headers): - # Handle fields extracted from a Pydantic Model for a header, each field - # doesn't have a FieldInfo of type Header with the default convert_underscores=True - convert_underscores = getattr( - field.field_info, "convert_underscores", default_convert_underscores - ) - if convert_underscores: - alias = get_validation_alias(field) - if alias == field.name: - alias = alias.replace("_", "-") - value = _get_multidict_value(field, received_params, alias=alias) - if value is not None: - params_to_process[get_validation_alias(field)] = value - processed_keys.add(alias or get_validation_alias(field)) - # For headers with convert_underscores=True, mark both the converted - # header name and the original field alias as processed to avoid - # accepting the original alias as an extra header. - processed_keys.add(get_validation_alias(field)) - - for key in received_params.keys(): - if key not in processed_keys: - if isinstance(received_params, (ImmutableMultiDict, Headers)): - value = received_params.getlist(key) - if isinstance(value, list) and (len(value) == 1): - params_to_process[key] = value[0] - else: - params_to_process[key] = value - else: - params_to_process[key] = received_params.get(key) - - if single_not_embedded_field: - field_info = first_field.field_info - assert isinstance(field_info, params.Param), ( - "Params must be subclasses of Param" - ) - loc: tuple[str, ...] = (field_info.in_.value,) - v_, errors_ = _validate_value_with_model_field( - field=first_field, value=params_to_process, values=values, loc=loc - ) - return {first_field.name: v_}, errors_ - - for field in fields: - value = _get_multidict_value(field, received_params) - field_info = field.field_info - assert isinstance(field_info, params.Param), ( - "Params must be subclasses of Param" - ) - loc = (field_info.in_.value, get_validation_alias(field)) - v_, errors_ = _validate_value_with_model_field( - field=field, value=value, values=values, loc=loc - ) - if errors_: - errors.extend(errors_) - else: - values[field.name] = v_ - return values, errors - - -def is_union_of_base_models(field_type: Any) -> bool: - """Check if field type is a Union where all members are BaseModel subclasses.""" - from fastapi.types import UnionType - - origin = get_origin(field_type) - - # Check if it's a Union type (covers both typing.Union and types.UnionType in Python 3.10+) - if origin is not Union and origin is not UnionType: - return False - - union_args = get_args(field_type) - - for arg in union_args: - if not lenient_issubclass(arg, BaseModel): - return False - - return True - - -def _should_embed_body_fields(fields: list[ModelField]) -> bool: - if not fields: - return False - # More than one dependency could have the same field, it would show up as multiple - # fields but it's the same one, so count them by name - body_param_names_set = {field.name for field in fields} - # A top level field has to be a single field, not multiple - if len(body_param_names_set) > 1: - return True - first_field = fields[0] - # If it explicitly specifies it is embedded, it has to be embedded - if getattr(first_field.field_info, "embed", None): - return True - # If it's a Form (or File) field, it has to be a BaseModel (or a union of BaseModels) to be top level - # otherwise it has to be embedded, so that the key value pair can be extracted - if ( - isinstance(first_field.field_info, params.Form) - and not lenient_issubclass(first_field.field_info.annotation, BaseModel) - and not is_union_of_base_models(first_field.field_info.annotation) - ): - return True - return False - - -async def _extract_form_body( - body_fields: list[ModelField], - received_body: FormData, -) -> dict[str, Any]: - values = {} - - for field in body_fields: - value = _get_multidict_value(field, received_body) - field_info = field.field_info - if ( - isinstance(field_info, params.File) - and is_bytes_or_nonable_bytes_annotation(field.field_info.annotation) - and isinstance(value, UploadFile) - ): - value = await value.read() - elif ( - is_bytes_sequence_annotation(field.field_info.annotation) - and isinstance(field_info, params.File) - and value_is_sequence(value) - ): - # For types - assert isinstance(value, sequence_types) - results: list[bytes | str] = [] - for sub_value in value: - results.append(await sub_value.read()) - value = serialize_sequence_value(field=field, value=results) - if value is not None: - values[get_validation_alias(field)] = value - field_aliases = {get_validation_alias(field) for field in body_fields} - for key in received_body.keys(): - if key not in field_aliases: - param_values = received_body.getlist(key) - if len(param_values) == 1: - values[key] = param_values[0] - else: - values[key] = param_values - return values - - -async def request_body_to_args( - body_fields: list[ModelField], - received_body: dict[str, Any] | FormData | bytes | None, - embed_body_fields: bool, -) -> tuple[dict[str, Any], list[dict[str, Any]]]: - values: dict[str, Any] = {} - errors: list[dict[str, Any]] = [] - assert body_fields, "request_body_to_args() should be called with fields" - single_not_embedded_field = len(body_fields) == 1 and not embed_body_fields - first_field = body_fields[0] - body_to_process = received_body - - fields_to_extract: list[ModelField] = body_fields - - if ( - single_not_embedded_field - and lenient_issubclass(first_field.field_info.annotation, BaseModel) - and isinstance(received_body, FormData) - ): - fields_to_extract = get_cached_model_fields(first_field.field_info.annotation) - - if isinstance(received_body, FormData): - body_to_process = await _extract_form_body(fields_to_extract, received_body) - - if single_not_embedded_field: - loc: tuple[str, ...] = ("body",) - v_, errors_ = _validate_value_with_model_field( - field=first_field, value=body_to_process, values=values, loc=loc - ) - return {first_field.name: v_}, errors_ - for field in body_fields: - loc = ("body", get_validation_alias(field)) - value: Any | None = None - if body_to_process is not None and not isinstance(body_to_process, bytes): - try: - value = body_to_process.get(get_validation_alias(field)) - # If the received body is a list, not a dict - except AttributeError: - errors.append(get_missing_field_error(loc)) - continue - v_, errors_ = _validate_value_with_model_field( - field=field, value=value, values=values, loc=loc - ) - if errors_: - errors.extend(errors_) - else: - values[field.name] = v_ - return values, errors - - -def get_body_field( - *, flat_dependant: Dependant, name: str, embed_body_fields: bool -) -> ModelField | None: - """ - Get a ModelField representing the request body for a path operation, combining - all body parameters into a single field if necessary. - - Used to check if it's form data (with `isinstance(body_field, params.Form)`) - or JSON and to generate the JSON Schema for a request body. - - This is **not** used to validate/parse the request body, that's done with each - individual body parameter. - """ - if not flat_dependant.body_params: - return None - first_param = flat_dependant.body_params[0] - if not embed_body_fields: - return first_param - model_name = "Body_" + name - BodyModel = create_body_model( - fields=flat_dependant.body_params, model_name=model_name - ) - required = any( - True for f in flat_dependant.body_params if f.field_info.is_required() - ) - BodyFieldInfo_kwargs: dict[str, Any] = { - "annotation": BodyModel, - "alias": "body", - } - if not required: - BodyFieldInfo_kwargs["default"] = None - if any(isinstance(f.field_info, params.File) for f in flat_dependant.body_params): - BodyFieldInfo: type[params.Body] = params.File - elif any(isinstance(f.field_info, params.Form) for f in flat_dependant.body_params): - BodyFieldInfo = params.Form - else: - BodyFieldInfo = params.Body - - body_param_media_types = [ - f.field_info.media_type - for f in flat_dependant.body_params - if isinstance(f.field_info, params.Body) - ] - if len(set(body_param_media_types)) == 1: - BodyFieldInfo_kwargs["media_type"] = body_param_media_types[0] - final_field = create_model_field( - name="body", - type_=BodyModel, - alias="body", - field_info=BodyFieldInfo(**BodyFieldInfo_kwargs), - ) - return final_field - - -def get_validation_alias(field: ModelField) -> str: - va = getattr(field, "validation_alias", None) - return va or field.alias diff --git a/server/venv/Lib/site-packages/fastapi/encoders.py b/server/venv/Lib/site-packages/fastapi/encoders.py deleted file mode 100644 index c9f882d..0000000 --- a/server/venv/Lib/site-packages/fastapi/encoders.py +++ /dev/null @@ -1,364 +0,0 @@ -import dataclasses -import datetime -from collections import defaultdict, deque -from collections.abc import Callable -from decimal import Decimal -from enum import Enum -from ipaddress import ( - IPv4Address, - IPv4Interface, - IPv4Network, - IPv6Address, - IPv6Interface, - IPv6Network, -) -from pathlib import Path, PurePath -from re import Pattern -from types import GeneratorType -from typing import Annotated, Any -from uuid import UUID - -from annotated_doc import Doc -from fastapi.exceptions import PydanticV1NotSupportedError -from fastapi.types import IncEx -from pydantic import BaseModel -from pydantic.networks import AnyUrl, NameEmail -from pydantic.types import SecretBytes, SecretStr -from pydantic_core import PydanticUndefinedType - -from ._compat import ( - Url, - is_pydantic_v1_model_instance, -) - -try: - # pydantic.color.Color is deprecated since v2.0b3, but supporting for bwd-compat - from pydantic.color import Color # ty: ignore[deprecated] -except ImportError: # pragma: no cover - - class Color: # type: ignore[no-redef] - pass - - -try: - # Supporting the new Color format for newer versions of Pydantic - from pydantic_extra_types.color import Color as PyExtraColor -except ImportError: # pragma: no cover - - class PyExtraColor: # type: ignore[no-redef] - pass - - -# Taken from Pydantic v1 as is -def isoformat(o: datetime.date | datetime.time) -> str: - return o.isoformat() - - -# Adapted from Pydantic v1 -# TODO: pv2 should this return strings instead? -def decimal_encoder(dec_value: Decimal) -> int | float: - """ - Encodes a Decimal as int if there's no exponent, otherwise float - - This is useful when we use ConstrainedDecimal to represent Numeric(x,0) - where an integer (but not int typed) is used. Encoding this as a float - results in failed round-tripping between encode and parse. - Our Id type is a prime example of this. - - >>> decimal_encoder(Decimal("1.0")) - 1.0 - - >>> decimal_encoder(Decimal("1")) - 1 - - >>> decimal_encoder(Decimal("NaN")) - nan - """ - exponent = dec_value.as_tuple().exponent - if isinstance(exponent, int) and exponent >= 0: - return int(dec_value) - else: - return float(dec_value) - - -ENCODERS_BY_TYPE: dict[type[Any], Callable[[Any], Any]] = { - bytes: lambda o: o.decode(), - Color: str, - PyExtraColor: str, - datetime.date: isoformat, - datetime.datetime: isoformat, - datetime.time: isoformat, - datetime.timedelta: lambda td: td.total_seconds(), - Decimal: decimal_encoder, - Enum: lambda o: o.value, - frozenset: list, - deque: list, - GeneratorType: list, - IPv4Address: str, - IPv4Interface: str, - IPv4Network: str, - IPv6Address: str, - IPv6Interface: str, - IPv6Network: str, - NameEmail: str, - Path: str, - Pattern: lambda o: o.pattern, - SecretBytes: str, - SecretStr: str, - set: list, - UUID: str, - Url: str, - AnyUrl: str, -} - - -def generate_encoders_by_class_tuples( - type_encoder_map: dict[Any, Callable[[Any], Any]], -) -> dict[Callable[[Any], Any], tuple[Any, ...]]: - encoders_by_class_tuples: dict[Callable[[Any], Any], tuple[Any, ...]] = defaultdict( - tuple - ) - for type_, encoder in type_encoder_map.items(): - encoders_by_class_tuples[encoder] += (type_,) - return encoders_by_class_tuples - - -encoders_by_class_tuples = generate_encoders_by_class_tuples(ENCODERS_BY_TYPE) - - -def jsonable_encoder( - obj: Annotated[ - Any, - Doc( - """ - The input object to convert to JSON. - """ - ), - ], - include: Annotated[ - IncEx | None, - Doc( - """ - Pydantic's `include` parameter, passed to Pydantic models to set the - fields to include. - """ - ), - ] = None, - exclude: Annotated[ - IncEx | None, - Doc( - """ - Pydantic's `exclude` parameter, passed to Pydantic models to set the - fields to exclude. - """ - ), - ] = None, - by_alias: Annotated[ - bool, - Doc( - """ - Pydantic's `by_alias` parameter, passed to Pydantic models to define if - the output should use the alias names (when provided) or the Python - attribute names. In an API, if you set an alias, it's probably because you - want to use it in the result, so you probably want to leave this set to - `True`. - """ - ), - ] = True, - exclude_unset: Annotated[ - bool, - Doc( - """ - Pydantic's `exclude_unset` parameter, passed to Pydantic models to define - if it should exclude from the output the fields that were not explicitly - set (and that only had their default values). - """ - ), - ] = False, - exclude_defaults: Annotated[ - bool, - Doc( - """ - Pydantic's `exclude_defaults` parameter, passed to Pydantic models to define - if it should exclude from the output the fields that had the same default - value, even when they were explicitly set. - """ - ), - ] = False, - exclude_none: Annotated[ - bool, - Doc( - """ - Pydantic's `exclude_none` parameter, passed to Pydantic models to define - if it should exclude from the output any fields that have a `None` value. - """ - ), - ] = False, - custom_encoder: Annotated[ - dict[Any, Callable[[Any], Any]] | None, - Doc( - """ - Pydantic's `custom_encoder` parameter, passed to Pydantic models to define - a custom encoder. - """ - ), - ] = None, - sqlalchemy_safe: Annotated[ - bool, - Doc( - """ - Exclude from the output any fields that start with the name `_sa`. - - This is mainly a hack for compatibility with SQLAlchemy objects, they - store internal SQLAlchemy-specific state in attributes named with `_sa`, - and those objects can't (and shouldn't be) serialized to JSON. - """ - ), - ] = True, -) -> Any: - """ - Convert any object to something that can be encoded in JSON. - - This is used internally by FastAPI to make sure anything you return can be - encoded as JSON before it is sent to the client. - - You can also use it yourself, for example to convert objects before saving them - in a database that supports only JSON. - - Read more about it in the - [FastAPI docs for JSON Compatible Encoder](https://fastapi.tiangolo.com/tutorial/encoder/). - """ - custom_encoder = custom_encoder or {} - if custom_encoder: - if type(obj) in custom_encoder: - return custom_encoder[type(obj)](obj) - else: - for encoder_type, encoder_instance in custom_encoder.items(): - if isinstance(obj, encoder_type): - return encoder_instance(obj) - if include is not None and not isinstance(include, (set, dict)): - include = set(include) # type: ignore[assignment] # ty: ignore[invalid-assignment] - if exclude is not None and not isinstance(exclude, (set, dict)): - exclude = set(exclude) # type: ignore[assignment] # ty: ignore[invalid-assignment] - if isinstance(obj, BaseModel): - obj_dict = obj.model_dump( - mode="json", - include=include, - exclude=exclude, - by_alias=by_alias, - exclude_unset=exclude_unset, - exclude_none=exclude_none, - exclude_defaults=exclude_defaults, - ) - return jsonable_encoder( - obj_dict, - exclude_none=exclude_none, - exclude_defaults=exclude_defaults, - sqlalchemy_safe=sqlalchemy_safe, - ) - if dataclasses.is_dataclass(obj): - assert not isinstance(obj, type) - obj_dict = dataclasses.asdict(obj) - return jsonable_encoder( - obj_dict, - include=include, - exclude=exclude, - by_alias=by_alias, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - custom_encoder=custom_encoder, - sqlalchemy_safe=sqlalchemy_safe, - ) - if isinstance(obj, Enum): - return obj.value - if isinstance(obj, PurePath): - return str(obj) - if isinstance(obj, (str, int, float, type(None))): - return obj - if isinstance(obj, PydanticUndefinedType): - return None - if isinstance(obj, dict): - encoded_dict = {} - allowed_keys = set(obj.keys()) - if include is not None: - allowed_keys &= set(include) - if exclude is not None: - allowed_keys -= set(exclude) - for key, value in obj.items(): - if ( - ( - not sqlalchemy_safe - or (not isinstance(key, str)) - or (not key.startswith("_sa")) - ) - and (value is not None or not exclude_none) - and key in allowed_keys - ): - encoded_key = jsonable_encoder( - key, - by_alias=by_alias, - exclude_unset=exclude_unset, - exclude_none=exclude_none, - custom_encoder=custom_encoder, - sqlalchemy_safe=sqlalchemy_safe, - ) - encoded_value = jsonable_encoder( - value, - by_alias=by_alias, - exclude_unset=exclude_unset, - exclude_none=exclude_none, - custom_encoder=custom_encoder, - sqlalchemy_safe=sqlalchemy_safe, - ) - encoded_dict[encoded_key] = encoded_value - return encoded_dict - if isinstance(obj, (list, set, frozenset, GeneratorType, tuple, deque)): - encoded_list = [] - for item in obj: - encoded_list.append( - jsonable_encoder( - item, - include=include, - exclude=exclude, - by_alias=by_alias, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - custom_encoder=custom_encoder, - sqlalchemy_safe=sqlalchemy_safe, - ) - ) - return encoded_list - - if type(obj) in ENCODERS_BY_TYPE: - return ENCODERS_BY_TYPE[type(obj)](obj) - for encoder, classes_tuple in encoders_by_class_tuples.items(): - if isinstance(obj, classes_tuple): - return encoder(obj) - if is_pydantic_v1_model_instance(obj): - raise PydanticV1NotSupportedError( - "pydantic.v1 models are no longer supported by FastAPI." - f" Please update the model {obj!r}." - ) - try: - data = dict(obj) - except Exception as e: - errors: list[Exception] = [] - errors.append(e) - try: - data = vars(obj) - except Exception as e: - errors.append(e) - raise ValueError(errors) from e - return jsonable_encoder( - data, - include=include, - exclude=exclude, - by_alias=by_alias, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - custom_encoder=custom_encoder, - sqlalchemy_safe=sqlalchemy_safe, - ) diff --git a/server/venv/Lib/site-packages/fastapi/exception_handlers.py b/server/venv/Lib/site-packages/fastapi/exception_handlers.py deleted file mode 100644 index 475dd7b..0000000 --- a/server/venv/Lib/site-packages/fastapi/exception_handlers.py +++ /dev/null @@ -1,34 +0,0 @@ -from fastapi.encoders import jsonable_encoder -from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError -from fastapi.utils import is_body_allowed_for_status_code -from fastapi.websockets import WebSocket -from starlette.exceptions import HTTPException -from starlette.requests import Request -from starlette.responses import JSONResponse, Response -from starlette.status import WS_1008_POLICY_VIOLATION - - -async def http_exception_handler(request: Request, exc: HTTPException) -> Response: - headers = getattr(exc, "headers", None) - if not is_body_allowed_for_status_code(exc.status_code): - return Response(status_code=exc.status_code, headers=headers) - return JSONResponse( - {"detail": exc.detail}, status_code=exc.status_code, headers=headers - ) - - -async def request_validation_exception_handler( - request: Request, exc: RequestValidationError -) -> JSONResponse: - return JSONResponse( - status_code=422, - content={"detail": jsonable_encoder(exc.errors())}, - ) - - -async def websocket_request_validation_exception_handler( - websocket: WebSocket, exc: WebSocketRequestValidationError -) -> None: - await websocket.close( - code=WS_1008_POLICY_VIOLATION, reason=jsonable_encoder(exc.errors()) - ) diff --git a/server/venv/Lib/site-packages/fastapi/exceptions.py b/server/venv/Lib/site-packages/fastapi/exceptions.py deleted file mode 100644 index d7065c5..0000000 --- a/server/venv/Lib/site-packages/fastapi/exceptions.py +++ /dev/null @@ -1,256 +0,0 @@ -from collections.abc import Mapping, Sequence -from typing import Annotated, Any, TypedDict - -from annotated_doc import Doc -from pydantic import BaseModel, create_model -from starlette.exceptions import HTTPException as StarletteHTTPException -from starlette.exceptions import WebSocketException as StarletteWebSocketException - - -class EndpointContext(TypedDict, total=False): - function: str - path: str - file: str - line: int - - -class HTTPException(StarletteHTTPException): - """ - An HTTP exception you can raise in your own code to show errors to the client. - - This is for client errors, invalid authentication, invalid data, etc. Not for server - errors in your code. - - Read more about it in the - [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/). - - ## Example - - ```python - from fastapi import FastAPI, HTTPException - - app = FastAPI() - - items = {"foo": "The Foo Wrestlers"} - - - @app.get("/items/{item_id}") - async def read_item(item_id: str): - if item_id not in items: - raise HTTPException(status_code=404, detail="Item not found") - return {"item": items[item_id]} - ``` - """ - - def __init__( - self, - status_code: Annotated[ - int, - Doc( - """ - HTTP status code to send to the client. - - Read more about it in the - [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/#use-httpexception) - """ - ), - ], - detail: Annotated[ - Any, - Doc( - """ - Any data to be sent to the client in the `detail` key of the JSON - response. - - Read more about it in the - [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/#use-httpexception) - """ - ), - ] = None, - headers: Annotated[ - Mapping[str, str] | None, - Doc( - """ - Any headers to send to the client in the response. - - Read more about it in the - [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/#add-custom-headers) - - """ - ), - ] = None, - ) -> None: - super().__init__(status_code=status_code, detail=detail, headers=headers) - - -class WebSocketException(StarletteWebSocketException): - """ - A WebSocket exception you can raise in your own code to show errors to the client. - - This is for client errors, invalid authentication, invalid data, etc. Not for server - errors in your code. - - Read more about it in the - [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/). - - ## Example - - ```python - from typing import Annotated - - from fastapi import ( - Cookie, - FastAPI, - WebSocket, - WebSocketException, - status, - ) - - app = FastAPI() - - @app.websocket("/items/{item_id}/ws") - async def websocket_endpoint( - *, - websocket: WebSocket, - session: Annotated[str | None, Cookie()] = None, - item_id: str, - ): - if session is None: - raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION) - await websocket.accept() - while True: - data = await websocket.receive_text() - await websocket.send_text(f"Session cookie is: {session}") - await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}") - ``` - """ - - def __init__( - self, - code: Annotated[ - int, - Doc( - """ - A closing code from the - [valid codes defined in the specification](https://datatracker.ietf.org/doc/html/rfc6455#section-7.4.1). - """ - ), - ], - reason: Annotated[ - str | None, - Doc( - """ - The reason to close the WebSocket connection. - - It is UTF-8-encoded data. The interpretation of the reason is up to the - application, it is not specified by the WebSocket specification. - - It could contain text that could be human-readable or interpretable - by the client code, etc. - """ - ), - ] = None, - ) -> None: - super().__init__(code=code, reason=reason) - - -RequestErrorModel: type[BaseModel] = create_model("Request") -WebSocketErrorModel: type[BaseModel] = create_model("WebSocket") - - -class FastAPIError(RuntimeError): - """ - A generic, FastAPI-specific error. - """ - - -class DependencyScopeError(FastAPIError): - """ - A dependency declared that it depends on another dependency with an invalid - (narrower) scope. - """ - - -class ValidationException(Exception): - def __init__( - self, - errors: Sequence[Any], - *, - endpoint_ctx: EndpointContext | None = None, - ) -> None: - self._errors = errors - self.endpoint_ctx = endpoint_ctx - - ctx = endpoint_ctx or {} - self.endpoint_function = ctx.get("function") - self.endpoint_path = ctx.get("path") - self.endpoint_file = ctx.get("file") - self.endpoint_line = ctx.get("line") - - def errors(self) -> Sequence[Any]: - return self._errors - - def _format_endpoint_context(self) -> str: - if not (self.endpoint_file and self.endpoint_line and self.endpoint_function): - if self.endpoint_path: - return f"\n Endpoint: {self.endpoint_path}" - return "" - - context = f'\n File "{self.endpoint_file}", line {self.endpoint_line}, in {self.endpoint_function}' - if self.endpoint_path: - context += f"\n {self.endpoint_path}" - return context - - def __str__(self) -> str: - message = f"{len(self._errors)} validation error{'s' if len(self._errors) != 1 else ''}:\n" - for err in self._errors: - message += f" {err}\n" - message += self._format_endpoint_context() - return message.rstrip() - - -class RequestValidationError(ValidationException): - def __init__( - self, - errors: Sequence[Any], - *, - body: Any = None, - endpoint_ctx: EndpointContext | None = None, - ) -> None: - super().__init__(errors, endpoint_ctx=endpoint_ctx) - self.body = body - - -class WebSocketRequestValidationError(ValidationException): - def __init__( - self, - errors: Sequence[Any], - *, - endpoint_ctx: EndpointContext | None = None, - ) -> None: - super().__init__(errors, endpoint_ctx=endpoint_ctx) - - -class ResponseValidationError(ValidationException): - def __init__( - self, - errors: Sequence[Any], - *, - body: Any = None, - endpoint_ctx: EndpointContext | None = None, - ) -> None: - super().__init__(errors, endpoint_ctx=endpoint_ctx) - self.body = body - - -class PydanticV1NotSupportedError(FastAPIError): - """ - A pydantic.v1 model is used, which is no longer supported. - """ - - -class FastAPIDeprecationWarning(UserWarning): - """ - A custom deprecation warning as DeprecationWarning is ignored - Ref: https://sethmlarson.dev/deprecations-via-warnings-dont-work-for-python-libraries - """ diff --git a/server/venv/Lib/site-packages/fastapi/logger.py b/server/venv/Lib/site-packages/fastapi/logger.py deleted file mode 100644 index 5b2c4ad..0000000 --- a/server/venv/Lib/site-packages/fastapi/logger.py +++ /dev/null @@ -1,3 +0,0 @@ -import logging - -logger = logging.getLogger("fastapi") diff --git a/server/venv/Lib/site-packages/fastapi/middleware/__init__.py b/server/venv/Lib/site-packages/fastapi/middleware/__init__.py deleted file mode 100644 index 620296d..0000000 --- a/server/venv/Lib/site-packages/fastapi/middleware/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from starlette.middleware import Middleware as Middleware diff --git a/server/venv/Lib/site-packages/fastapi/middleware/asyncexitstack.py b/server/venv/Lib/site-packages/fastapi/middleware/asyncexitstack.py deleted file mode 100644 index 4ce3f5a..0000000 --- a/server/venv/Lib/site-packages/fastapi/middleware/asyncexitstack.py +++ /dev/null @@ -1,18 +0,0 @@ -from contextlib import AsyncExitStack - -from starlette.types import ASGIApp, Receive, Scope, Send - - -# Used mainly to close files after the request is done, dependencies are closed -# in their own AsyncExitStack -class AsyncExitStackMiddleware: - def __init__( - self, app: ASGIApp, context_name: str = "fastapi_middleware_astack" - ) -> None: - self.app = app - self.context_name = context_name - - async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: - async with AsyncExitStack() as stack: - scope[self.context_name] = stack - await self.app(scope, receive, send) diff --git a/server/venv/Lib/site-packages/fastapi/middleware/cors.py b/server/venv/Lib/site-packages/fastapi/middleware/cors.py deleted file mode 100644 index 8dfaad0..0000000 --- a/server/venv/Lib/site-packages/fastapi/middleware/cors.py +++ /dev/null @@ -1 +0,0 @@ -from starlette.middleware.cors import CORSMiddleware as CORSMiddleware # noqa diff --git a/server/venv/Lib/site-packages/fastapi/middleware/gzip.py b/server/venv/Lib/site-packages/fastapi/middleware/gzip.py deleted file mode 100644 index bbeb2cc..0000000 --- a/server/venv/Lib/site-packages/fastapi/middleware/gzip.py +++ /dev/null @@ -1 +0,0 @@ -from starlette.middleware.gzip import GZipMiddleware as GZipMiddleware # noqa diff --git a/server/venv/Lib/site-packages/fastapi/middleware/httpsredirect.py b/server/venv/Lib/site-packages/fastapi/middleware/httpsredirect.py deleted file mode 100644 index b7a3d8e..0000000 --- a/server/venv/Lib/site-packages/fastapi/middleware/httpsredirect.py +++ /dev/null @@ -1,3 +0,0 @@ -from starlette.middleware.httpsredirect import ( # noqa - HTTPSRedirectMiddleware as HTTPSRedirectMiddleware, -) diff --git a/server/venv/Lib/site-packages/fastapi/middleware/trustedhost.py b/server/venv/Lib/site-packages/fastapi/middleware/trustedhost.py deleted file mode 100644 index 08d7e03..0000000 --- a/server/venv/Lib/site-packages/fastapi/middleware/trustedhost.py +++ /dev/null @@ -1,3 +0,0 @@ -from starlette.middleware.trustedhost import ( # noqa - TrustedHostMiddleware as TrustedHostMiddleware, -) diff --git a/server/venv/Lib/site-packages/fastapi/middleware/wsgi.py b/server/venv/Lib/site-packages/fastapi/middleware/wsgi.py deleted file mode 100644 index 69e4dca..0000000 --- a/server/venv/Lib/site-packages/fastapi/middleware/wsgi.py +++ /dev/null @@ -1,3 +0,0 @@ -from starlette.middleware.wsgi import ( - WSGIMiddleware as WSGIMiddleware, -) # pragma: no cover # noqa diff --git a/server/venv/Lib/site-packages/fastapi/openapi/__init__.py b/server/venv/Lib/site-packages/fastapi/openapi/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/venv/Lib/site-packages/fastapi/openapi/constants.py b/server/venv/Lib/site-packages/fastapi/openapi/constants.py deleted file mode 100644 index d724ee3..0000000 --- a/server/venv/Lib/site-packages/fastapi/openapi/constants.py +++ /dev/null @@ -1,3 +0,0 @@ -METHODS_WITH_BODY = {"GET", "HEAD", "POST", "PUT", "DELETE", "PATCH"} -REF_PREFIX = "#/components/schemas/" -REF_TEMPLATE = "#/components/schemas/{model}" diff --git a/server/venv/Lib/site-packages/fastapi/openapi/docs.py b/server/venv/Lib/site-packages/fastapi/openapi/docs.py deleted file mode 100644 index 0d9242f..0000000 --- a/server/venv/Lib/site-packages/fastapi/openapi/docs.py +++ /dev/null @@ -1,389 +0,0 @@ -import json -from typing import Annotated, Any - -from annotated_doc import Doc -from fastapi.encoders import jsonable_encoder -from starlette.responses import HTMLResponse - - -def _html_safe_json(value: Any) -> str: - """Serialize a value to JSON with HTML special characters escaped. - - This prevents injection when the JSON is embedded inside a - - - - - """ - return HTMLResponse(html) - - -def get_redoc_html( - *, - openapi_url: Annotated[ - str, - Doc( - """ - The OpenAPI URL that ReDoc should load and use. - - This is normally done automatically by FastAPI using the default URL - `/openapi.json`. - - Read more about it in the - [FastAPI docs for Conditional OpenAPI](https://fastapi.tiangolo.com/how-to/conditional-openapi/#conditional-openapi-from-settings-and-env-vars) - """ - ), - ], - title: Annotated[ - str, - Doc( - """ - The HTML `` content, normally shown in the browser tab. - - Read more about it in the - [FastAPI docs for Custom Docs UI Static Assets](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/) - """ - ), - ], - redoc_js_url: Annotated[ - str, - Doc( - """ - The URL to use to load the ReDoc JavaScript. - - It is normally set to a CDN URL. - - Read more about it in the - [FastAPI docs for Custom Docs UI Static Assets](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/) - """ - ), - ] = "https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js", - redoc_favicon_url: Annotated[ - str, - Doc( - """ - The URL of the favicon to use. It is normally shown in the browser tab. - """ - ), - ] = "https://fastapi.tiangolo.com/img/favicon.png", - with_google_fonts: Annotated[ - bool, - Doc( - """ - Load and use Google Fonts. - """ - ), - ] = True, -) -> HTMLResponse: - """ - Generate and return the HTML response that loads ReDoc for the alternative - API docs (normally served at `/redoc`). - - You would only call this function yourself if you needed to override some parts, - for example the URLs to use to load ReDoc's JavaScript and CSS. - - Read more about it in the - [FastAPI docs for Custom Docs UI Static Assets (Self-Hosting)](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/). - """ - html = f""" - <!DOCTYPE html> - <html> - <head> - <title>{title} - - - - """ - if with_google_fonts: - html += """ - - """ - html += f""" - - - - - - - - - - - """ - return HTMLResponse(html) - - -def get_swagger_ui_oauth2_redirect_html() -> HTMLResponse: - """ - Generate the HTML response with the OAuth2 redirection for Swagger UI. - - You normally don't need to use or change this. - """ - # copied from https://github.com/swagger-api/swagger-ui/blob/v4.14.0/dist/oauth2-redirect.html - html = """ - - - - Swagger UI: OAuth2 Redirect - - - - - - """ - return HTMLResponse(content=html) diff --git a/server/venv/Lib/site-packages/fastapi/openapi/models.py b/server/venv/Lib/site-packages/fastapi/openapi/models.py deleted file mode 100644 index ca26bf9..0000000 --- a/server/venv/Lib/site-packages/fastapi/openapi/models.py +++ /dev/null @@ -1,435 +0,0 @@ -from collections.abc import Callable, Iterable, Mapping -from enum import Enum -from typing import Annotated, Any, Literal, Optional, Union - -from fastapi._compat import with_info_plain_validator_function -from fastapi.logger import logger -from pydantic import ( - AnyUrl, - BaseModel, - Field, - GetJsonSchemaHandler, -) -from typing_extensions import TypedDict -from typing_extensions import deprecated as typing_deprecated - -try: - import email_validator - - assert email_validator # make autoflake ignore the unused import - from pydantic import EmailStr -except ImportError: # pragma: no cover - - class EmailStr(str): # type: ignore[no-redef] - @classmethod - def __get_validators__(cls) -> Iterable[Callable[..., Any]]: - yield cls.validate - - @classmethod - def validate(cls, v: Any) -> str: - logger.warning( - "email-validator not installed, email fields will be treated as str.\n" - "To install, run: pip install email-validator" - ) - return str(v) - - @classmethod - def _validate(cls, __input_value: Any, _: Any) -> str: - logger.warning( - "email-validator not installed, email fields will be treated as str.\n" - "To install, run: pip install email-validator" - ) - return str(__input_value) - - @classmethod - def __get_pydantic_json_schema__( - cls, core_schema: Mapping[str, Any], handler: GetJsonSchemaHandler - ) -> dict[str, Any]: - return {"type": "string", "format": "email"} - - @classmethod - def __get_pydantic_core_schema__( - cls, source: type[Any], handler: Callable[[Any], Mapping[str, Any]] - ) -> Mapping[str, Any]: - return with_info_plain_validator_function(cls._validate) - - -class BaseModelWithConfig(BaseModel): - model_config = {"extra": "allow"} - - -class Contact(BaseModelWithConfig): - name: str | None = None - url: AnyUrl | None = None - email: EmailStr | None = None - - -class License(BaseModelWithConfig): - name: str - identifier: str | None = None - url: AnyUrl | None = None - - -class Info(BaseModelWithConfig): - title: str - summary: str | None = None - description: str | None = None - termsOfService: str | None = None - contact: Contact | None = None - license: License | None = None - version: str - - -class ServerVariable(BaseModelWithConfig): - enum: Annotated[list[str] | None, Field(min_length=1)] = None - default: str - description: str | None = None - - -class Server(BaseModelWithConfig): - url: AnyUrl | str - description: str | None = None - variables: dict[str, ServerVariable] | None = None - - -class Reference(BaseModel): - ref: str = Field(alias="$ref") - - -class Discriminator(BaseModel): - propertyName: str - mapping: dict[str, str] | None = None - - -class XML(BaseModelWithConfig): - name: str | None = None - namespace: str | None = None - prefix: str | None = None - attribute: bool | None = None - wrapped: bool | None = None - - -class ExternalDocumentation(BaseModelWithConfig): - description: str | None = None - url: AnyUrl - - -# Ref JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation#name-type -SchemaType = Literal[ - "array", "boolean", "integer", "null", "number", "object", "string" -] - - -class Schema(BaseModelWithConfig): - # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-json-schema-core-vocabu - # Core Vocabulary - schema_: str | None = Field(default=None, alias="$schema") - vocabulary: str | None = Field(default=None, alias="$vocabulary") - id: str | None = Field(default=None, alias="$id") - anchor: str | None = Field(default=None, alias="$anchor") - dynamicAnchor: str | None = Field(default=None, alias="$dynamicAnchor") - ref: str | None = Field(default=None, alias="$ref") - dynamicRef: str | None = Field(default=None, alias="$dynamicRef") - defs: dict[str, "SchemaOrBool"] | None = Field(default=None, alias="$defs") - comment: str | None = Field(default=None, alias="$comment") - # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-a-vocabulary-for-applying-s - # A Vocabulary for Applying Subschemas - allOf: list["SchemaOrBool"] | None = None - anyOf: list["SchemaOrBool"] | None = None - oneOf: list["SchemaOrBool"] | None = None - not_: Optional["SchemaOrBool"] = Field(default=None, alias="not") - if_: Optional["SchemaOrBool"] = Field(default=None, alias="if") - then: Optional["SchemaOrBool"] = None - else_: Optional["SchemaOrBool"] = Field(default=None, alias="else") - dependentSchemas: dict[str, "SchemaOrBool"] | None = None - prefixItems: list["SchemaOrBool"] | None = None - items: Optional["SchemaOrBool"] = None - contains: Optional["SchemaOrBool"] = None - properties: dict[str, "SchemaOrBool"] | None = None - patternProperties: dict[str, "SchemaOrBool"] | None = None - additionalProperties: Optional["SchemaOrBool"] = None - propertyNames: Optional["SchemaOrBool"] = None - unevaluatedItems: Optional["SchemaOrBool"] = None - unevaluatedProperties: Optional["SchemaOrBool"] = None - # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-structural - # A Vocabulary for Structural Validation - type: SchemaType | list[SchemaType] | None = None - enum: list[Any] | None = None - const: Any | None = None - multipleOf: float | None = Field(default=None, gt=0) - maximum: float | None = None - exclusiveMaximum: float | None = None - minimum: float | None = None - exclusiveMinimum: float | None = None - maxLength: int | None = Field(default=None, ge=0) - minLength: int | None = Field(default=None, ge=0) - pattern: str | None = None - maxItems: int | None = Field(default=None, ge=0) - minItems: int | None = Field(default=None, ge=0) - uniqueItems: bool | None = None - maxContains: int | None = Field(default=None, ge=0) - minContains: int | None = Field(default=None, ge=0) - maxProperties: int | None = Field(default=None, ge=0) - minProperties: int | None = Field(default=None, ge=0) - required: list[str] | None = None - dependentRequired: dict[str, set[str]] | None = None - # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-vocabularies-for-semantic-c - # Vocabularies for Semantic Content With "format" - format: str | None = None - # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-the-conten - # A Vocabulary for the Contents of String-Encoded Data - contentEncoding: str | None = None - contentMediaType: str | None = None - contentSchema: Optional["SchemaOrBool"] = None - # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-basic-meta - # A Vocabulary for Basic Meta-Data Annotations - title: str | None = None - description: str | None = None - default: Any | None = None - deprecated: bool | None = None - readOnly: bool | None = None - writeOnly: bool | None = None - examples: list[Any] | None = None - # Ref: OpenAPI 3.1.0: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schema-object - # Schema Object - discriminator: Discriminator | None = None - xml: XML | None = None - externalDocs: ExternalDocumentation | None = None - example: Annotated[ - Any | None, - typing_deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = None - - -# Ref: https://json-schema.org/draft/2020-12/json-schema-core.html#name-json-schema-documents -# A JSON Schema MUST be an object or a boolean. -SchemaOrBool = Schema | bool - - -class Example(TypedDict, total=False): - summary: str | None - description: str | None - value: Any | None - externalValue: AnyUrl | None - - __pydantic_config__ = {"extra": "allow"} # type: ignore[misc] # ty: ignore[invalid-typed-dict-statement] - - -class ParameterInType(Enum): - query = "query" - header = "header" - path = "path" - cookie = "cookie" - - -class Encoding(BaseModelWithConfig): - contentType: str | None = None - headers: dict[str, Union["Header", Reference]] | None = None - style: str | None = None - explode: bool | None = None - allowReserved: bool | None = None - - -class MediaType(BaseModelWithConfig): - schema_: Schema | Reference | None = Field(default=None, alias="schema") - example: Any | None = None - examples: dict[str, Example | Reference] | None = None - encoding: dict[str, Encoding] | None = None - - -class ParameterBase(BaseModelWithConfig): - description: str | None = None - required: bool | None = None - deprecated: bool | None = None - # Serialization rules for simple scenarios - style: str | None = None - explode: bool | None = None - allowReserved: bool | None = None - schema_: Schema | Reference | None = Field(default=None, alias="schema") - example: Any | None = None - examples: dict[str, Example | Reference] | None = None - # Serialization rules for more complex scenarios - content: dict[str, MediaType] | None = None - - -class Parameter(ParameterBase): - name: str - in_: ParameterInType = Field(alias="in") - - -class Header(ParameterBase): - pass - - -class RequestBody(BaseModelWithConfig): - description: str | None = None - content: dict[str, MediaType] - required: bool | None = None - - -class Link(BaseModelWithConfig): - operationRef: str | None = None - operationId: str | None = None - parameters: dict[str, Any | str] | None = None - requestBody: Any | str | None = None - description: str | None = None - server: Server | None = None - - -class Response(BaseModelWithConfig): - description: str - headers: dict[str, Header | Reference] | None = None - content: dict[str, MediaType] | None = None - links: dict[str, Link | Reference] | None = None - - -class Operation(BaseModelWithConfig): - tags: list[str] | None = None - summary: str | None = None - description: str | None = None - externalDocs: ExternalDocumentation | None = None - operationId: str | None = None - parameters: list[Parameter | Reference] | None = None - requestBody: RequestBody | Reference | None = None - # Using Any for Specification Extensions - responses: dict[str, Response | Any] | None = None - callbacks: dict[str, dict[str, "PathItem"] | Reference] | None = None - deprecated: bool | None = None - security: list[dict[str, list[str]]] | None = None - servers: list[Server] | None = None - - -class PathItem(BaseModelWithConfig): - ref: str | None = Field(default=None, alias="$ref") - summary: str | None = None - description: str | None = None - get: Operation | None = None - put: Operation | None = None - post: Operation | None = None - delete: Operation | None = None - options: Operation | None = None - head: Operation | None = None - patch: Operation | None = None - trace: Operation | None = None - servers: list[Server] | None = None - parameters: list[Parameter | Reference] | None = None - - -class SecuritySchemeType(Enum): - apiKey = "apiKey" - http = "http" - oauth2 = "oauth2" - openIdConnect = "openIdConnect" - - -class SecurityBase(BaseModelWithConfig): - type_: SecuritySchemeType = Field(alias="type") - description: str | None = None - - -class APIKeyIn(Enum): - query = "query" - header = "header" - cookie = "cookie" - - -class APIKey(SecurityBase): - type_: SecuritySchemeType = Field(default=SecuritySchemeType.apiKey, alias="type") - in_: APIKeyIn = Field(alias="in") - name: str - - -class HTTPBase(SecurityBase): - type_: SecuritySchemeType = Field(default=SecuritySchemeType.http, alias="type") - scheme: str - - -class HTTPBearer(HTTPBase): - scheme: Literal["bearer"] = "bearer" - bearerFormat: str | None = None - - -class OAuthFlow(BaseModelWithConfig): - refreshUrl: str | None = None - scopes: dict[str, str] = {} - - -class OAuthFlowImplicit(OAuthFlow): - authorizationUrl: str - - -class OAuthFlowPassword(OAuthFlow): - tokenUrl: str - - -class OAuthFlowClientCredentials(OAuthFlow): - tokenUrl: str - - -class OAuthFlowAuthorizationCode(OAuthFlow): - authorizationUrl: str - tokenUrl: str - - -class OAuthFlows(BaseModelWithConfig): - implicit: OAuthFlowImplicit | None = None - password: OAuthFlowPassword | None = None - clientCredentials: OAuthFlowClientCredentials | None = None - authorizationCode: OAuthFlowAuthorizationCode | None = None - - -class OAuth2(SecurityBase): - type_: SecuritySchemeType = Field(default=SecuritySchemeType.oauth2, alias="type") - flows: OAuthFlows - - -class OpenIdConnect(SecurityBase): - type_: SecuritySchemeType = Field( - default=SecuritySchemeType.openIdConnect, alias="type" - ) - openIdConnectUrl: str - - -SecurityScheme = APIKey | HTTPBase | OAuth2 | OpenIdConnect | HTTPBearer - - -class Components(BaseModelWithConfig): - schemas: dict[str, Schema | Reference] | None = None - responses: dict[str, Response | Reference] | None = None - parameters: dict[str, Parameter | Reference] | None = None - examples: dict[str, Example | Reference] | None = None - requestBodies: dict[str, RequestBody | Reference] | None = None - headers: dict[str, Header | Reference] | None = None - securitySchemes: dict[str, SecurityScheme | Reference] | None = None - links: dict[str, Link | Reference] | None = None - # Using Any for Specification Extensions - callbacks: dict[str, dict[str, PathItem] | Reference | Any] | None = None - pathItems: dict[str, PathItem | Reference] | None = None - - -class Tag(BaseModelWithConfig): - name: str - description: str | None = None - externalDocs: ExternalDocumentation | None = None - - -class OpenAPI(BaseModelWithConfig): - openapi: str - info: Info - jsonSchemaDialect: str | None = None - servers: list[Server] | None = None - # Using Any for Specification Extensions - paths: dict[str, PathItem | Any] | None = None - webhooks: dict[str, PathItem | Reference] | None = None - components: Components | None = None - security: list[dict[str, list[str]]] | None = None - tags: list[Tag] | None = None - externalDocs: ExternalDocumentation | None = None - - -Schema.model_rebuild() -Operation.model_rebuild() -Encoding.model_rebuild() diff --git a/server/venv/Lib/site-packages/fastapi/openapi/utils.py b/server/venv/Lib/site-packages/fastapi/openapi/utils.py deleted file mode 100644 index 2e0aca1..0000000 --- a/server/venv/Lib/site-packages/fastapi/openapi/utils.py +++ /dev/null @@ -1,617 +0,0 @@ -import copy -import http.client -import inspect -import warnings -from collections.abc import Sequence -from typing import Any, Literal, cast - -from fastapi import routing -from fastapi._compat import ( - ModelField, - get_definitions, - get_flat_models_from_fields, - get_model_name_map, - get_schema_from_model_field, - lenient_issubclass, -) -from fastapi.datastructures import DefaultPlaceholder, _Unset -from fastapi.dependencies.models import Dependant -from fastapi.dependencies.utils import ( - _get_flat_fields_from_params, - get_flat_dependant, - get_flat_params, - get_validation_alias, -) -from fastapi.encoders import jsonable_encoder -from fastapi.exceptions import FastAPIDeprecationWarning -from fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX -from fastapi.openapi.models import OpenAPI -from fastapi.params import Body, ParamTypes -from fastapi.responses import Response -from fastapi.sse import _SSE_EVENT_SCHEMA -from fastapi.types import ModelNameMap -from fastapi.utils import ( - deep_dict_update, - generate_operation_id_for_path, - is_body_allowed_for_status_code, -) -from pydantic import BaseModel -from starlette.responses import JSONResponse -from starlette.routing import BaseRoute - -validation_error_definition = { - "title": "ValidationError", - "type": "object", - "properties": { - "loc": { - "title": "Location", - "type": "array", - "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, - }, - "msg": {"title": "Message", "type": "string"}, - "type": {"title": "Error Type", "type": "string"}, - "input": {"title": "Input"}, - "ctx": {"title": "Context", "type": "object"}, - }, - "required": ["loc", "msg", "type"], -} - -validation_error_response_definition = { - "title": "HTTPValidationError", - "type": "object", - "properties": { - "detail": { - "title": "Detail", - "type": "array", - "items": {"$ref": REF_PREFIX + "ValidationError"}, - } - }, -} - -status_code_ranges: dict[str, str] = { - "1XX": "Information", - "2XX": "Success", - "3XX": "Redirection", - "4XX": "Client Error", - "5XX": "Server Error", - "DEFAULT": "Default Response", -} - - -def get_openapi_security_definitions( - flat_dependant: Dependant, -) -> tuple[dict[str, Any], list[dict[str, Any]]]: - security_definitions = {} - # Use a dict to merge scopes for same security scheme - operation_security_dict: dict[str, list[str]] = {} - for security_dependency in flat_dependant._security_dependencies: - security_definition = jsonable_encoder( - security_dependency._security_scheme.model, - by_alias=True, - exclude_none=True, - ) - security_name = security_dependency._security_scheme.scheme_name - security_definitions[security_name] = security_definition - # Merge scopes for the same security scheme - if security_name not in operation_security_dict: - operation_security_dict[security_name] = [] - for scope in security_dependency.oauth_scopes or []: - if scope not in operation_security_dict[security_name]: - operation_security_dict[security_name].append(scope) - operation_security = [ - {name: scopes} for name, scopes in operation_security_dict.items() - ] - return security_definitions, operation_security - - -def _get_openapi_operation_parameters( - *, - dependant: Dependant, - model_name_map: ModelNameMap, - field_mapping: dict[ - tuple[ModelField, Literal["validation", "serialization"]], dict[str, Any] - ], - separate_input_output_schemas: bool = True, -) -> list[dict[str, Any]]: - parameters = [] - flat_dependant = get_flat_dependant(dependant, skip_repeats=True) - path_params = _get_flat_fields_from_params(flat_dependant.path_params) - query_params = _get_flat_fields_from_params(flat_dependant.query_params) - header_params = _get_flat_fields_from_params(flat_dependant.header_params) - cookie_params = _get_flat_fields_from_params(flat_dependant.cookie_params) - parameter_groups = [ - (ParamTypes.path, path_params), - (ParamTypes.query, query_params), - (ParamTypes.header, header_params), - (ParamTypes.cookie, cookie_params), - ] - default_convert_underscores = True - if len(flat_dependant.header_params) == 1: - first_field = flat_dependant.header_params[0] - if lenient_issubclass(first_field.field_info.annotation, BaseModel): - default_convert_underscores = getattr( - first_field.field_info, "convert_underscores", True - ) - for param_type, param_group in parameter_groups: - for param in param_group: - field_info = param.field_info - # field_info = cast(Param, field_info) - if not getattr(field_info, "include_in_schema", True): - continue - param_schema = get_schema_from_model_field( - field=param, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - name = get_validation_alias(param) - convert_underscores = getattr( - param.field_info, - "convert_underscores", - default_convert_underscores, - ) - if ( - param_type == ParamTypes.header - and name == param.name - and convert_underscores - ): - name = param.name.replace("_", "-") - - parameter = { - "name": name, - "in": param_type.value, - "required": param.field_info.is_required(), - "schema": param_schema, - } - if field_info.description: - parameter["description"] = field_info.description - openapi_examples = getattr(field_info, "openapi_examples", None) - example = getattr(field_info, "example", None) - if openapi_examples: - parameter["examples"] = jsonable_encoder(openapi_examples) - elif example is not _Unset: - parameter["example"] = jsonable_encoder(example) - if getattr(field_info, "deprecated", None): - parameter["deprecated"] = True - parameters.append(parameter) - return parameters - - -def get_openapi_operation_request_body( - *, - body_field: ModelField | None, - model_name_map: ModelNameMap, - field_mapping: dict[ - tuple[ModelField, Literal["validation", "serialization"]], dict[str, Any] - ], - separate_input_output_schemas: bool = True, -) -> dict[str, Any] | None: - if not body_field: - return None - assert isinstance(body_field, ModelField) - body_schema = get_schema_from_model_field( - field=body_field, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - field_info = cast(Body, body_field.field_info) - request_media_type = field_info.media_type - required = body_field.field_info.is_required() - request_body_oai: dict[str, Any] = {} - if required: - request_body_oai["required"] = required - request_media_content: dict[str, Any] = {"schema": body_schema} - if field_info.openapi_examples: - request_media_content["examples"] = jsonable_encoder( - field_info.openapi_examples - ) - elif field_info.example is not _Unset: - request_media_content["example"] = jsonable_encoder(field_info.example) - request_body_oai["content"] = {request_media_type: request_media_content} - return request_body_oai - - -def generate_operation_id( - *, route: routing._APIRouteLike, method: str -) -> str: # pragma: nocover - warnings.warn( - message="fastapi.openapi.utils.generate_operation_id() was deprecated, " - "it is not used internally, and will be removed soon", - category=FastAPIDeprecationWarning, - stacklevel=2, - ) - if route.operation_id: - return route.operation_id - path: str = route.path_format - return generate_operation_id_for_path(name=route.name, path=path, method=method) - - -def generate_operation_summary(*, route: routing._APIRouteLike, method: str) -> str: - if route.summary: - return route.summary - return route.name.replace("_", " ").title() - - -def get_openapi_operation_metadata( - *, route: routing._APIRouteLike, method: str, operation_ids: set[str] -) -> dict[str, Any]: - operation: dict[str, Any] = {} - if route.tags: - operation["tags"] = route.tags - operation["summary"] = generate_operation_summary(route=route, method=method) - if route.description: - operation["description"] = route.description - operation_id = route.operation_id or route.unique_id - if operation_id in operation_ids: - endpoint_name = getattr(route.endpoint, "__name__", "") - message = f"Duplicate Operation ID {operation_id} for function {endpoint_name}" - file_name = getattr(route.endpoint, "__globals__", {}).get("__file__") - if file_name: - message += f" at {file_name}" - warnings.warn(message, stacklevel=1) - operation_ids.add(operation_id) - operation["operationId"] = operation_id - if route.deprecated: - operation["deprecated"] = route.deprecated - return operation - - -def get_openapi_path( - *, - route: routing._APIRouteLike, - operation_ids: set[str], - model_name_map: ModelNameMap, - field_mapping: dict[ - tuple[ModelField, Literal["validation", "serialization"]], dict[str, Any] - ], - separate_input_output_schemas: bool = True, -) -> tuple[dict[str, Any], dict[str, Any], dict[str, Any]]: - path = {} - security_schemes: dict[str, Any] = {} - definitions: dict[str, Any] = {} - assert route.methods is not None, "Methods must be a list" - if isinstance(route.response_class, DefaultPlaceholder): - current_response_class: type[Response] = route.response_class.value - else: - current_response_class = route.response_class - assert current_response_class, "A response class is needed to generate OpenAPI" - route_response_media_type: str | None = current_response_class.media_type - if route.include_in_schema: - for method in route.methods: - operation = get_openapi_operation_metadata( - route=route, method=method, operation_ids=operation_ids - ) - parameters: list[dict[str, Any]] = [] - flat_dependant = get_flat_dependant(route.dependant, skip_repeats=True) - security_definitions, operation_security = get_openapi_security_definitions( - flat_dependant=flat_dependant - ) - if operation_security: - operation.setdefault("security", []).extend(operation_security) - if security_definitions: - security_schemes.update(security_definitions) - operation_parameters = _get_openapi_operation_parameters( - dependant=route.dependant, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - parameters.extend(operation_parameters) - if parameters: - all_parameters = { - (param["in"], param["name"]): param for param in parameters - } - required_parameters = { - (param["in"], param["name"]): param - for param in parameters - if param.get("required") - } - # Make sure required definitions of the same parameter take precedence - # over non-required definitions - all_parameters.update(required_parameters) - operation["parameters"] = list(all_parameters.values()) - if method in METHODS_WITH_BODY: - request_body_oai = get_openapi_operation_request_body( - body_field=route.body_field, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - if request_body_oai: - operation["requestBody"] = request_body_oai - if route.callbacks: - callbacks = {} - for callback in route.callbacks: - if isinstance(callback, routing.APIRoute): - ( - cb_path, - cb_security_schemes, - cb_definitions, - ) = get_openapi_path( - route=cast(routing._APIRouteLike, callback), - operation_ids=operation_ids, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - callbacks[callback.name] = {callback.path: cb_path} - operation["callbacks"] = callbacks - if route.status_code is not None: - status_code = str(route.status_code) - else: - # It would probably make more sense for all response classes to have an - # explicit default status_code, and to extract it from them, instead of - # doing this inspection tricks, that would probably be in the future - # TODO: probably make status_code a default class attribute for all - # responses in Starlette - response_signature = inspect.signature(current_response_class.__init__) - status_code_param = response_signature.parameters.get("status_code") - if status_code_param is not None: - if isinstance(status_code_param.default, int): - status_code = str(status_code_param.default) - operation.setdefault("responses", {}).setdefault(status_code, {})[ - "description" - ] = route.response_description - if is_body_allowed_for_status_code(route.status_code): - # Check for JSONL streaming (generator endpoints) - if route.is_json_stream: - jsonl_content: dict[str, Any] = {} - if route.stream_item_field: - item_schema = get_schema_from_model_field( - field=route.stream_item_field, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - jsonl_content["itemSchema"] = item_schema - else: - jsonl_content["itemSchema"] = {} - operation.setdefault("responses", {}).setdefault( - status_code, {} - ).setdefault("content", {})["application/jsonl"] = jsonl_content - elif route.is_sse_stream: - sse_content: dict[str, Any] = {} - item_schema = copy.deepcopy(_SSE_EVENT_SCHEMA) - if route.stream_item_field: - content_schema = get_schema_from_model_field( - field=route.stream_item_field, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - item_schema["required"] = ["data"] - item_schema["properties"]["data"] = { - "type": "string", - "contentMediaType": "application/json", - "contentSchema": content_schema, - } - sse_content["itemSchema"] = item_schema - operation.setdefault("responses", {}).setdefault( - status_code, {} - ).setdefault("content", {})["text/event-stream"] = sse_content - elif route_response_media_type: - response_schema = {"type": "string"} - if lenient_issubclass(current_response_class, JSONResponse): - if route.response_field: - response_schema = get_schema_from_model_field( - field=route.response_field, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - else: - response_schema = {} - operation.setdefault("responses", {}).setdefault( - status_code, {} - ).setdefault("content", {}).setdefault( - route_response_media_type, {} - )["schema"] = response_schema - if route.responses: - operation_responses = operation.setdefault("responses", {}) - for ( - additional_status_code, - additional_response, - ) in route.responses.items(): - process_response = copy.deepcopy(additional_response) - process_response.pop("model", None) - status_code_key = str(additional_status_code).upper() - if status_code_key == "DEFAULT": - status_code_key = "default" - openapi_response = operation_responses.setdefault( - status_code_key, {} - ) - assert isinstance(process_response, dict), ( - "An additional response must be a dict" - ) - field = route.response_fields.get(additional_status_code) - additional_field_schema: dict[str, Any] | None = None - if field: - additional_field_schema = get_schema_from_model_field( - field=field, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - media_type = route_response_media_type or "application/json" - additional_schema = ( - process_response.setdefault("content", {}) - .setdefault(media_type, {}) - .setdefault("schema", {}) - ) - deep_dict_update(additional_schema, additional_field_schema) - status_text: str | None = status_code_ranges.get( - str(additional_status_code).upper() - ) or http.client.responses.get(int(additional_status_code)) - description = ( - process_response.get("description") - or openapi_response.get("description") - or status_text - or "Additional Response" - ) - deep_dict_update(openapi_response, process_response) - openapi_response["description"] = description - http422 = "422" - all_route_params = get_flat_params(route.dependant) - if (all_route_params or route.body_field) and not any( - status in operation["responses"] - for status in [http422, "4XX", "default"] - ): - operation["responses"][http422] = { - "description": "Validation Error", - "content": { - "application/json": { - "schema": {"$ref": REF_PREFIX + "HTTPValidationError"} - } - }, - } - if "ValidationError" not in definitions: - definitions.update( - { - "ValidationError": validation_error_definition, - "HTTPValidationError": validation_error_response_definition, - } - ) - if route.openapi_extra: - deep_dict_update(operation, route.openapi_extra) - path[method.lower()] = operation - return path, security_schemes, definitions - - -def _get_api_route_for_openapi( - route_context: routing.RouteContext, -) -> routing._APIRouteLike | None: - if isinstance(route_context.original_route, routing.APIRoute): - return cast(routing._APIRouteLike, route_context) - return None - - -def get_fields_from_routes( - routes: Sequence[BaseRoute | routing.RouteContext], -) -> list[ModelField]: - body_fields_from_routes: list[ModelField] = [] - responses_from_routes: list[ModelField] = [] - request_fields_from_routes: list[ModelField] = [] - callback_flat_models: list[ModelField] = [] - for route_context in routing.iter_route_contexts(routes): - api_route = _get_api_route_for_openapi(route_context) - if api_route is None: - continue - if api_route.include_in_schema: - if api_route.body_field: - assert isinstance(api_route.body_field, ModelField), ( - "A request body must be a Pydantic Field" - ) - body_fields_from_routes.append(api_route.body_field) - if api_route.response_field: - responses_from_routes.append(api_route.response_field) - if api_route.response_fields: - responses_from_routes.extend(api_route.response_fields.values()) - if api_route.stream_item_field: - responses_from_routes.append(api_route.stream_item_field) - if api_route.callbacks: - callback_flat_models.extend(get_fields_from_routes(api_route.callbacks)) - params = get_flat_params(api_route.dependant) - request_fields_from_routes.extend(params) - - flat_models = callback_flat_models + list( - body_fields_from_routes + responses_from_routes + request_fields_from_routes - ) - return flat_models - - -def get_openapi( - *, - title: str, - version: str, - openapi_version: str = "3.1.0", - summary: str | None = None, - description: str | None = None, - routes: Sequence[BaseRoute | routing.RouteContext], - webhooks: Sequence[BaseRoute | routing.RouteContext] | None = None, - tags: list[dict[str, Any]] | None = None, - servers: list[dict[str, str | Any]] | None = None, - terms_of_service: str | None = None, - contact: dict[str, str | Any] | None = None, - license_info: dict[str, str | Any] | None = None, - separate_input_output_schemas: bool = True, - external_docs: dict[str, Any] | None = None, -) -> dict[str, Any]: - info: dict[str, Any] = {"title": title, "version": version} - if summary: - info["summary"] = summary - if description: - info["description"] = description - if terms_of_service: - info["termsOfService"] = terms_of_service - if contact: - info["contact"] = contact - if license_info: - info["license"] = license_info - output: dict[str, Any] = {"openapi": openapi_version, "info": info} - if servers: - output["servers"] = servers - components: dict[str, dict[str, Any]] = {} - paths: dict[str, dict[str, Any]] = {} - webhook_paths: dict[str, dict[str, Any]] = {} - operation_ids: set[str] = set() - all_fields = get_fields_from_routes(list(routes) + list(webhooks or [])) - flat_models = get_flat_models_from_fields(all_fields, known_models=set()) - model_name_map = get_model_name_map(flat_models) - field_mapping, definitions = get_definitions( - fields=all_fields, - model_name_map=model_name_map, - separate_input_output_schemas=separate_input_output_schemas, - ) - for route_context in routing.iter_route_contexts(routes): - api_route = _get_api_route_for_openapi(route_context) - if api_route is not None: - result = get_openapi_path( - route=api_route, - operation_ids=operation_ids, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - if result: - path, security_schemes, path_definitions = result - if path: - paths.setdefault(api_route.path_format, {}).update(path) - if security_schemes: - components.setdefault("securitySchemes", {}).update( - security_schemes - ) - if path_definitions: - definitions.update(path_definitions) - for webhook_context in routing.iter_route_contexts(webhooks or []): - api_webhook = _get_api_route_for_openapi(webhook_context) - if api_webhook is not None: - result = get_openapi_path( - route=api_webhook, - operation_ids=operation_ids, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - if result: - path, security_schemes, path_definitions = result - if path: - webhook_paths.setdefault(api_webhook.path_format, {}).update(path) - if security_schemes: - components.setdefault("securitySchemes", {}).update( - security_schemes - ) - if path_definitions: - definitions.update(path_definitions) - if definitions: - components["schemas"] = {k: definitions[k] for k in sorted(definitions)} - if components: - output["components"] = components - output["paths"] = paths - if webhook_paths: - output["webhooks"] = webhook_paths - if tags: - output["tags"] = tags - if external_docs: - output["externalDocs"] = external_docs - return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True) # type: ignore[no-any-return] diff --git a/server/venv/Lib/site-packages/fastapi/param_functions.py b/server/venv/Lib/site-packages/fastapi/param_functions.py deleted file mode 100644 index 1856178..0000000 --- a/server/venv/Lib/site-packages/fastapi/param_functions.py +++ /dev/null @@ -1,2460 +0,0 @@ -from collections.abc import Callable, Sequence -from typing import Annotated, Any, Literal - -from annotated_doc import Doc -from fastapi import params -from fastapi._compat import Undefined -from fastapi.datastructures import _Unset -from fastapi.openapi.models import Example -from pydantic import AliasChoices, AliasPath -from typing_extensions import deprecated - - -def Path( # noqa: N802 - default: Annotated[ - Any, - Doc( - """ - Default value if the parameter field is not set. - - This doesn't affect `Path` parameters as the value is always required. - The parameter is available only for compatibility. - """ - ), - ] = ..., - *, - default_factory: Annotated[ - Callable[[], Any] | None, - Doc( - """ - A callable to generate the default value. - - This doesn't affect `Path` parameters as the value is always required. - The parameter is available only for compatibility. - """ - ), - ] = _Unset, - alias: Annotated[ - str | None, - Doc( - """ - An alternative name for the parameter field. - - This will be used to extract the data and for the generated OpenAPI. - It is particularly useful when you can't use the name you want because it - is a Python reserved keyword or similar. - """ - ), - ] = None, - alias_priority: Annotated[ - int | None, - Doc( - """ - Priority of the alias. This affects whether an alias generator is used. - """ - ), - ] = _Unset, - validation_alias: Annotated[ - str | AliasPath | AliasChoices | None, - Doc( - """ - 'Whitelist' validation step. The parameter field will be the single one - allowed by the alias or set of aliases defined. - """ - ), - ] = None, - serialization_alias: Annotated[ - str | None, - Doc( - """ - 'Blacklist' validation step. The vanilla parameter field will be the - single one of the alias' or set of aliases' fields and all the other - fields will be ignored at serialization time. - """ - ), - ] = None, - title: Annotated[ - str | None, - Doc( - """ - Human-readable title. - - Read more about it in the - [FastAPI docs for Path Parameters and Numeric Validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#declare-metadata) - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - Human-readable description. - """ - ), - ] = None, - gt: Annotated[ - float | None, - Doc( - """ - Greater than. If set, value must be greater than this. Only applicable to - numbers. - - Read more about it in the - [FastAPI docs about Path parameters numeric validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#number-validations-greater-than-and-less-than-or-equal) - """ - ), - ] = None, - ge: Annotated[ - float | None, - Doc( - """ - Greater than or equal. If set, value must be greater than or equal to - this. Only applicable to numbers. - - Read more about it in the - [FastAPI docs about Path parameters numeric validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#number-validations-greater-than-and-less-than-or-equal) - """ - ), - ] = None, - lt: Annotated[ - float | None, - Doc( - """ - Less than. If set, value must be less than this. Only applicable to numbers. - - Read more about it in the - [FastAPI docs about Path parameters numeric validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#number-validations-greater-than-and-less-than-or-equal) - """ - ), - ] = None, - le: Annotated[ - float | None, - Doc( - """ - Less than or equal. If set, value must be less than or equal to this. - Only applicable to numbers. - - Read more about it in the - [FastAPI docs about Path parameters numeric validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#number-validations-greater-than-and-less-than-or-equal) - """ - ), - ] = None, - min_length: Annotated[ - int | None, - Doc( - """ - Minimum length for strings. - """ - ), - ] = None, - max_length: Annotated[ - int | None, - Doc( - """ - Maximum length for strings. - """ - ), - ] = None, - pattern: Annotated[ - str | None, - Doc( - """ - RegEx pattern for strings. - """ - ), - ] = None, - regex: Annotated[ - str | None, - Doc( - """ - RegEx pattern for strings. - """ - ), - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Annotated[ - str | None, - Doc( - """ - Parameter field name for discriminating the type in a tagged union. - """ - ), - ] = None, - strict: Annotated[ - bool | None, - Doc( - """ - If `True`, strict validation is applied to the field. - """ - ), - ] = _Unset, - multiple_of: Annotated[ - float | None, - Doc( - """ - Value must be a multiple of this. Only applicable to numbers. - """ - ), - ] = _Unset, - allow_inf_nan: Annotated[ - bool | None, - Doc( - """ - Allow `inf`, `-inf`, `nan`. Only applicable to numbers. - """ - ), - ] = _Unset, - max_digits: Annotated[ - int | None, - Doc( - """ - Maximum number of digits allowed for decimal values. - """ - ), - ] = _Unset, - decimal_places: Annotated[ - int | None, - Doc( - """ - Maximum number of decimal places allowed for decimal values. - """ - ), - ] = _Unset, - examples: Annotated[ - list[Any] | None, - Doc( - """ - Example values for this field. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/) - """ - ), - ] = None, - example: Annotated[ - Any | None, - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Annotated[ - dict[str, Example] | None, - Doc( - """ - OpenAPI-specific examples. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Swagger UI (that provides the `/docs` interface) has better support for the - OpenAPI-specific examples than the JSON Schema `examples`, that's the main - use case for this. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). - """ - ), - ] = None, - deprecated: Annotated[ - deprecated | str | bool | None, - Doc( - """ - Mark this parameter field as deprecated. - - It will affect the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - To include (or not) this parameter field in the generated OpenAPI. - You probably don't need it, but it's available. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = True, - json_schema_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Any additional JSON schema data. - """ - ), - ] = None, - **extra: Annotated[ - Any, - Doc( - """ - Include extra fields used by the JSON Schema. - """ - ), - deprecated( - """ - The `extra` kwargs is deprecated. Use `json_schema_extra` instead. - """ - ), - ], -) -> Any: - """ - Declare a path parameter for a *path operation*. - - Read more about it in the - [FastAPI docs for Path Parameters and Numeric Validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/). - - ```python - from typing import Annotated - - from fastapi import FastAPI, Path - - app = FastAPI() - - - @app.get("/items/{item_id}") - async def read_items( - item_id: Annotated[int, Path(title="The ID of the item to get")], - ): - return {"item_id": item_id} - ``` - """ - return params.Path( - default=default, - default_factory=default_factory, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - example=example, - examples=examples, - openapi_examples=openapi_examples, - deprecated=deprecated, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -def Query( # noqa: N802 - default: Annotated[ - Any, - Doc( - """ - Default value if the parameter field is not set. - - Read more about it in the - [FastAPI docs about Query parameters](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#alternative-old-query-as-the-default-value) - """ - ), - ] = Undefined, - *, - default_factory: Annotated[ - Callable[[], Any] | None, - Doc( - """ - A callable to generate the default value. - - This doesn't affect `Path` parameters as the value is always required. - The parameter is available only for compatibility. - """ - ), - ] = _Unset, - alias: Annotated[ - str | None, - Doc( - """ - An alternative name for the parameter field. - - This will be used to extract the data and for the generated OpenAPI. - It is particularly useful when you can't use the name you want because it - is a Python reserved keyword or similar. - - Read more about it in the - [FastAPI docs about Query parameters](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#alias-parameters) - """ - ), - ] = None, - alias_priority: Annotated[ - int | None, - Doc( - """ - Priority of the alias. This affects whether an alias generator is used. - """ - ), - ] = _Unset, - validation_alias: Annotated[ - str | AliasPath | AliasChoices | None, - Doc( - """ - 'Whitelist' validation step. The parameter field will be the single one - allowed by the alias or set of aliases defined. - """ - ), - ] = None, - serialization_alias: Annotated[ - str | None, - Doc( - """ - 'Blacklist' validation step. The vanilla parameter field will be the - single one of the alias' or set of aliases' fields and all the other - fields will be ignored at serialization time. - """ - ), - ] = None, - title: Annotated[ - str | None, - Doc( - """ - Human-readable title. - - Read more about it in the - [FastAPI docs about Query parameters](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#declare-more-metadata) - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - Human-readable description. - - Read more about it in the - [FastAPI docs about Query parameters](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#declare-more-metadata) - """ - ), - ] = None, - gt: Annotated[ - float | None, - Doc( - """ - Greater than. If set, value must be greater than this. Only applicable to - numbers. - - Read more about it in the - [FastAPI docs about Path parameters numeric validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#number-validations-greater-than-and-less-than-or-equal) - """ - ), - ] = None, - ge: Annotated[ - float | None, - Doc( - """ - Greater than or equal. If set, value must be greater than or equal to - this. Only applicable to numbers. - - Read more about it in the - [FastAPI docs about Path parameters numeric validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#number-validations-greater-than-and-less-than-or-equal) - """ - ), - ] = None, - lt: Annotated[ - float | None, - Doc( - """ - Less than. If set, value must be less than this. Only applicable to numbers. - - Read more about it in the - [FastAPI docs about Path parameters numeric validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#number-validations-greater-than-and-less-than-or-equal) - """ - ), - ] = None, - le: Annotated[ - float | None, - Doc( - """ - Less than or equal. If set, value must be less than or equal to this. - Only applicable to numbers. - - Read more about it in the - [FastAPI docs about Path parameters numeric validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#number-validations-greater-than-and-less-than-or-equal) - """ - ), - ] = None, - min_length: Annotated[ - int | None, - Doc( - """ - Minimum length for strings. - - Read more about it in the - [FastAPI docs about Query parameters](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/) - """ - ), - ] = None, - max_length: Annotated[ - int | None, - Doc( - """ - Maximum length for strings. - - Read more about it in the - [FastAPI docs about Query parameters](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/) - """ - ), - ] = None, - pattern: Annotated[ - str | None, - Doc( - """ - RegEx pattern for strings. - - Read more about it in the - [FastAPI docs about Query parameters](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#add-regular-expressions - """ - ), - ] = None, - regex: Annotated[ - str | None, - Doc( - """ - RegEx pattern for strings. - """ - ), - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Annotated[ - str | None, - Doc( - """ - Parameter field name for discriminating the type in a tagged union. - """ - ), - ] = None, - strict: Annotated[ - bool | None, - Doc( - """ - If `True`, strict validation is applied to the field. - """ - ), - ] = _Unset, - multiple_of: Annotated[ - float | None, - Doc( - """ - Value must be a multiple of this. Only applicable to numbers. - """ - ), - ] = _Unset, - allow_inf_nan: Annotated[ - bool | None, - Doc( - """ - Allow `inf`, `-inf`, `nan`. Only applicable to numbers. - """ - ), - ] = _Unset, - max_digits: Annotated[ - int | None, - Doc( - """ - Maximum number of digits allowed for decimal values. - """ - ), - ] = _Unset, - decimal_places: Annotated[ - int | None, - Doc( - """ - Maximum number of decimal places allowed for decimal values. - """ - ), - ] = _Unset, - examples: Annotated[ - list[Any] | None, - Doc( - """ - Example values for this field. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/) - """ - ), - ] = None, - example: Annotated[ - Any | None, - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Annotated[ - dict[str, Example] | None, - Doc( - """ - OpenAPI-specific examples. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Swagger UI (that provides the `/docs` interface) has better support for the - OpenAPI-specific examples than the JSON Schema `examples`, that's the main - use case for this. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). - """ - ), - ] = None, - deprecated: Annotated[ - deprecated | str | bool | None, - Doc( - """ - Mark this parameter field as deprecated. - - It will affect the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs about Query parameters](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#deprecating-parameters) - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - To include (or not) this parameter field in the generated OpenAPI. - You probably don't need it, but it's available. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs about Query parameters](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi - """ - ), - ] = True, - json_schema_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Any additional JSON schema data. - """ - ), - ] = None, - **extra: Annotated[ - Any, - Doc( - """ - Include extra fields used by the JSON Schema. - """ - ), - deprecated( - """ - The `extra` kwargs is deprecated. Use `json_schema_extra` instead. - """ - ), - ], -) -> Any: - return params.Query( - default=default, - default_factory=default_factory, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - example=example, - examples=examples, - openapi_examples=openapi_examples, - deprecated=deprecated, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -def Header( # noqa: N802 - default: Annotated[ - Any, - Doc( - """ - Default value if the parameter field is not set. - """ - ), - ] = Undefined, - *, - default_factory: Annotated[ - Callable[[], Any] | None, - Doc( - """ - A callable to generate the default value. - - This doesn't affect `Path` parameters as the value is always required. - The parameter is available only for compatibility. - """ - ), - ] = _Unset, - alias: Annotated[ - str | None, - Doc( - """ - An alternative name for the parameter field. - - This will be used to extract the data and for the generated OpenAPI. - It is particularly useful when you can't use the name you want because it - is a Python reserved keyword or similar. - """ - ), - ] = None, - alias_priority: Annotated[ - int | None, - Doc( - """ - Priority of the alias. This affects whether an alias generator is used. - """ - ), - ] = _Unset, - validation_alias: Annotated[ - str | AliasPath | AliasChoices | None, - Doc( - """ - 'Whitelist' validation step. The parameter field will be the single one - allowed by the alias or set of aliases defined. - """ - ), - ] = None, - serialization_alias: Annotated[ - str | None, - Doc( - """ - 'Blacklist' validation step. The vanilla parameter field will be the - single one of the alias' or set of aliases' fields and all the other - fields will be ignored at serialization time. - """ - ), - ] = None, - convert_underscores: Annotated[ - bool, - Doc( - """ - Automatically convert underscores to hyphens in the parameter field name. - - Read more about it in the - [FastAPI docs for Header Parameters](https://fastapi.tiangolo.com/tutorial/header-params/#automatic-conversion) - """ - ), - ] = True, - title: Annotated[ - str | None, - Doc( - """ - Human-readable title. - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - Human-readable description. - """ - ), - ] = None, - gt: Annotated[ - float | None, - Doc( - """ - Greater than. If set, value must be greater than this. Only applicable to - numbers. - """ - ), - ] = None, - ge: Annotated[ - float | None, - Doc( - """ - Greater than or equal. If set, value must be greater than or equal to - this. Only applicable to numbers. - """ - ), - ] = None, - lt: Annotated[ - float | None, - Doc( - """ - Less than. If set, value must be less than this. Only applicable to numbers. - """ - ), - ] = None, - le: Annotated[ - float | None, - Doc( - """ - Less than or equal. If set, value must be less than or equal to this. - Only applicable to numbers. - """ - ), - ] = None, - min_length: Annotated[ - int | None, - Doc( - """ - Minimum length for strings. - """ - ), - ] = None, - max_length: Annotated[ - int | None, - Doc( - """ - Maximum length for strings. - """ - ), - ] = None, - pattern: Annotated[ - str | None, - Doc( - """ - RegEx pattern for strings. - """ - ), - ] = None, - regex: Annotated[ - str | None, - Doc( - """ - RegEx pattern for strings. - """ - ), - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Annotated[ - str | None, - Doc( - """ - Parameter field name for discriminating the type in a tagged union. - """ - ), - ] = None, - strict: Annotated[ - bool | None, - Doc( - """ - If `True`, strict validation is applied to the field. - """ - ), - ] = _Unset, - multiple_of: Annotated[ - float | None, - Doc( - """ - Value must be a multiple of this. Only applicable to numbers. - """ - ), - ] = _Unset, - allow_inf_nan: Annotated[ - bool | None, - Doc( - """ - Allow `inf`, `-inf`, `nan`. Only applicable to numbers. - """ - ), - ] = _Unset, - max_digits: Annotated[ - int | None, - Doc( - """ - Maximum number of digits allowed for decimal values. - """ - ), - ] = _Unset, - decimal_places: Annotated[ - int | None, - Doc( - """ - Maximum number of decimal places allowed for decimal values. - """ - ), - ] = _Unset, - examples: Annotated[ - list[Any] | None, - Doc( - """ - Example values for this field. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/) - """ - ), - ] = None, - example: Annotated[ - Any | None, - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Annotated[ - dict[str, Example] | None, - Doc( - """ - OpenAPI-specific examples. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Swagger UI (that provides the `/docs` interface) has better support for the - OpenAPI-specific examples than the JSON Schema `examples`, that's the main - use case for this. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). - """ - ), - ] = None, - deprecated: Annotated[ - deprecated | str | bool | None, - Doc( - """ - Mark this parameter field as deprecated. - - It will affect the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - To include (or not) this parameter field in the generated OpenAPI. - You probably don't need it, but it's available. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = True, - json_schema_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Any additional JSON schema data. - """ - ), - ] = None, - **extra: Annotated[ - Any, - Doc( - """ - Include extra fields used by the JSON Schema. - """ - ), - deprecated( - """ - The `extra` kwargs is deprecated. Use `json_schema_extra` instead. - """ - ), - ], -) -> Any: - return params.Header( - default=default, - default_factory=default_factory, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - convert_underscores=convert_underscores, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - example=example, - examples=examples, - openapi_examples=openapi_examples, - deprecated=deprecated, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -def Cookie( # noqa: N802 - default: Annotated[ - Any, - Doc( - """ - Default value if the parameter field is not set. - """ - ), - ] = Undefined, - *, - default_factory: Annotated[ - Callable[[], Any] | None, - Doc( - """ - A callable to generate the default value. - - This doesn't affect `Path` parameters as the value is always required. - The parameter is available only for compatibility. - """ - ), - ] = _Unset, - alias: Annotated[ - str | None, - Doc( - """ - An alternative name for the parameter field. - - This will be used to extract the data and for the generated OpenAPI. - It is particularly useful when you can't use the name you want because it - is a Python reserved keyword or similar. - """ - ), - ] = None, - alias_priority: Annotated[ - int | None, - Doc( - """ - Priority of the alias. This affects whether an alias generator is used. - """ - ), - ] = _Unset, - validation_alias: Annotated[ - str | AliasPath | AliasChoices | None, - Doc( - """ - 'Whitelist' validation step. The parameter field will be the single one - allowed by the alias or set of aliases defined. - """ - ), - ] = None, - serialization_alias: Annotated[ - str | None, - Doc( - """ - 'Blacklist' validation step. The vanilla parameter field will be the - single one of the alias' or set of aliases' fields and all the other - fields will be ignored at serialization time. - """ - ), - ] = None, - title: Annotated[ - str | None, - Doc( - """ - Human-readable title. - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - Human-readable description. - """ - ), - ] = None, - gt: Annotated[ - float | None, - Doc( - """ - Greater than. If set, value must be greater than this. Only applicable to - numbers. - """ - ), - ] = None, - ge: Annotated[ - float | None, - Doc( - """ - Greater than or equal. If set, value must be greater than or equal to - this. Only applicable to numbers. - """ - ), - ] = None, - lt: Annotated[ - float | None, - Doc( - """ - Less than. If set, value must be less than this. Only applicable to numbers. - """ - ), - ] = None, - le: Annotated[ - float | None, - Doc( - """ - Less than or equal. If set, value must be less than or equal to this. - Only applicable to numbers. - """ - ), - ] = None, - min_length: Annotated[ - int | None, - Doc( - """ - Minimum length for strings. - """ - ), - ] = None, - max_length: Annotated[ - int | None, - Doc( - """ - Maximum length for strings. - """ - ), - ] = None, - pattern: Annotated[ - str | None, - Doc( - """ - RegEx pattern for strings. - """ - ), - ] = None, - regex: Annotated[ - str | None, - Doc( - """ - RegEx pattern for strings. - """ - ), - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Annotated[ - str | None, - Doc( - """ - Parameter field name for discriminating the type in a tagged union. - """ - ), - ] = None, - strict: Annotated[ - bool | None, - Doc( - """ - If `True`, strict validation is applied to the field. - """ - ), - ] = _Unset, - multiple_of: Annotated[ - float | None, - Doc( - """ - Value must be a multiple of this. Only applicable to numbers. - """ - ), - ] = _Unset, - allow_inf_nan: Annotated[ - bool | None, - Doc( - """ - Allow `inf`, `-inf`, `nan`. Only applicable to numbers. - """ - ), - ] = _Unset, - max_digits: Annotated[ - int | None, - Doc( - """ - Maximum number of digits allowed for decimal values. - """ - ), - ] = _Unset, - decimal_places: Annotated[ - int | None, - Doc( - """ - Maximum number of decimal places allowed for decimal values. - """ - ), - ] = _Unset, - examples: Annotated[ - list[Any] | None, - Doc( - """ - Example values for this field. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/) - """ - ), - ] = None, - example: Annotated[ - Any | None, - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Annotated[ - dict[str, Example] | None, - Doc( - """ - OpenAPI-specific examples. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Swagger UI (that provides the `/docs` interface) has better support for the - OpenAPI-specific examples than the JSON Schema `examples`, that's the main - use case for this. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). - """ - ), - ] = None, - deprecated: Annotated[ - deprecated | str | bool | None, - Doc( - """ - Mark this parameter field as deprecated. - - It will affect the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - To include (or not) this parameter field in the generated OpenAPI. - You probably don't need it, but it's available. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = True, - json_schema_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Any additional JSON schema data. - """ - ), - ] = None, - **extra: Annotated[ - Any, - Doc( - """ - Include extra fields used by the JSON Schema. - """ - ), - deprecated( - """ - The `extra` kwargs is deprecated. Use `json_schema_extra` instead. - """ - ), - ], -) -> Any: - return params.Cookie( - default=default, - default_factory=default_factory, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - example=example, - examples=examples, - openapi_examples=openapi_examples, - deprecated=deprecated, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -def Body( # noqa: N802 - default: Annotated[ - Any, - Doc( - """ - Default value if the parameter field is not set. - """ - ), - ] = Undefined, - *, - default_factory: Annotated[ - Callable[[], Any] | None, - Doc( - """ - A callable to generate the default value. - - This doesn't affect `Path` parameters as the value is always required. - The parameter is available only for compatibility. - """ - ), - ] = _Unset, - embed: Annotated[ - bool | None, - Doc( - """ - When `embed` is `True`, the parameter will be expected in a JSON body as a - key instead of being the JSON body itself. - - This happens automatically when more than one `Body` parameter is declared. - - Read more about it in the - [FastAPI docs for Body - Multiple Parameters](https://fastapi.tiangolo.com/tutorial/body-multiple-params/#embed-a-single-body-parameter). - """ - ), - ] = None, - media_type: Annotated[ - str, - Doc( - """ - The media type of this parameter field. Changing it would affect the - generated OpenAPI, but currently it doesn't affect the parsing of the data. - """ - ), - ] = "application/json", - alias: Annotated[ - str | None, - Doc( - """ - An alternative name for the parameter field. - - This will be used to extract the data and for the generated OpenAPI. - It is particularly useful when you can't use the name you want because it - is a Python reserved keyword or similar. - """ - ), - ] = None, - alias_priority: Annotated[ - int | None, - Doc( - """ - Priority of the alias. This affects whether an alias generator is used. - """ - ), - ] = _Unset, - validation_alias: Annotated[ - str | AliasPath | AliasChoices | None, - Doc( - """ - 'Whitelist' validation step. The parameter field will be the single one - allowed by the alias or set of aliases defined. - """ - ), - ] = None, - serialization_alias: Annotated[ - str | None, - Doc( - """ - 'Blacklist' validation step. The vanilla parameter field will be the - single one of the alias' or set of aliases' fields and all the other - fields will be ignored at serialization time. - """ - ), - ] = None, - title: Annotated[ - str | None, - Doc( - """ - Human-readable title. - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - Human-readable description. - """ - ), - ] = None, - gt: Annotated[ - float | None, - Doc( - """ - Greater than. If set, value must be greater than this. Only applicable to - numbers. - """ - ), - ] = None, - ge: Annotated[ - float | None, - Doc( - """ - Greater than or equal. If set, value must be greater than or equal to - this. Only applicable to numbers. - """ - ), - ] = None, - lt: Annotated[ - float | None, - Doc( - """ - Less than. If set, value must be less than this. Only applicable to numbers. - """ - ), - ] = None, - le: Annotated[ - float | None, - Doc( - """ - Less than or equal. If set, value must be less than or equal to this. - Only applicable to numbers. - """ - ), - ] = None, - min_length: Annotated[ - int | None, - Doc( - """ - Minimum length for strings. - """ - ), - ] = None, - max_length: Annotated[ - int | None, - Doc( - """ - Maximum length for strings. - """ - ), - ] = None, - pattern: Annotated[ - str | None, - Doc( - """ - RegEx pattern for strings. - """ - ), - ] = None, - regex: Annotated[ - str | None, - Doc( - """ - RegEx pattern for strings. - """ - ), - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Annotated[ - str | None, - Doc( - """ - Parameter field name for discriminating the type in a tagged union. - """ - ), - ] = None, - strict: Annotated[ - bool | None, - Doc( - """ - If `True`, strict validation is applied to the field. - """ - ), - ] = _Unset, - multiple_of: Annotated[ - float | None, - Doc( - """ - Value must be a multiple of this. Only applicable to numbers. - """ - ), - ] = _Unset, - allow_inf_nan: Annotated[ - bool | None, - Doc( - """ - Allow `inf`, `-inf`, `nan`. Only applicable to numbers. - """ - ), - ] = _Unset, - max_digits: Annotated[ - int | None, - Doc( - """ - Maximum number of digits allowed for decimal values. - """ - ), - ] = _Unset, - decimal_places: Annotated[ - int | None, - Doc( - """ - Maximum number of decimal places allowed for decimal values. - """ - ), - ] = _Unset, - examples: Annotated[ - list[Any] | None, - Doc( - """ - Example values for this field. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/) - """ - ), - ] = None, - example: Annotated[ - Any | None, - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Annotated[ - dict[str, Example] | None, - Doc( - """ - OpenAPI-specific examples. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Swagger UI (that provides the `/docs` interface) has better support for the - OpenAPI-specific examples than the JSON Schema `examples`, that's the main - use case for this. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). - """ - ), - ] = None, - deprecated: Annotated[ - deprecated | str | bool | None, - Doc( - """ - Mark this parameter field as deprecated. - - It will affect the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - To include (or not) this parameter field in the generated OpenAPI. - You probably don't need it, but it's available. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = True, - json_schema_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Any additional JSON schema data. - """ - ), - ] = None, - **extra: Annotated[ - Any, - Doc( - """ - Include extra fields used by the JSON Schema. - """ - ), - deprecated( - """ - The `extra` kwargs is deprecated. Use `json_schema_extra` instead. - """ - ), - ], -) -> Any: - return params.Body( - default=default, - default_factory=default_factory, - embed=embed, - media_type=media_type, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - example=example, - examples=examples, - openapi_examples=openapi_examples, - deprecated=deprecated, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -def Form( # noqa: N802 - default: Annotated[ - Any, - Doc( - """ - Default value if the parameter field is not set. - """ - ), - ] = Undefined, - *, - default_factory: Annotated[ - Callable[[], Any] | None, - Doc( - """ - A callable to generate the default value. - - This doesn't affect `Path` parameters as the value is always required. - The parameter is available only for compatibility. - """ - ), - ] = _Unset, - media_type: Annotated[ - str, - Doc( - """ - The media type of this parameter field. Changing it would affect the - generated OpenAPI, but currently it doesn't affect the parsing of the data. - """ - ), - ] = "application/x-www-form-urlencoded", - alias: Annotated[ - str | None, - Doc( - """ - An alternative name for the parameter field. - - This will be used to extract the data and for the generated OpenAPI. - It is particularly useful when you can't use the name you want because it - is a Python reserved keyword or similar. - """ - ), - ] = None, - alias_priority: Annotated[ - int | None, - Doc( - """ - Priority of the alias. This affects whether an alias generator is used. - """ - ), - ] = _Unset, - validation_alias: Annotated[ - str | AliasPath | AliasChoices | None, - Doc( - """ - 'Whitelist' validation step. The parameter field will be the single one - allowed by the alias or set of aliases defined. - """ - ), - ] = None, - serialization_alias: Annotated[ - str | None, - Doc( - """ - 'Blacklist' validation step. The vanilla parameter field will be the - single one of the alias' or set of aliases' fields and all the other - fields will be ignored at serialization time. - """ - ), - ] = None, - title: Annotated[ - str | None, - Doc( - """ - Human-readable title. - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - Human-readable description. - """ - ), - ] = None, - gt: Annotated[ - float | None, - Doc( - """ - Greater than. If set, value must be greater than this. Only applicable to - numbers. - """ - ), - ] = None, - ge: Annotated[ - float | None, - Doc( - """ - Greater than or equal. If set, value must be greater than or equal to - this. Only applicable to numbers. - """ - ), - ] = None, - lt: Annotated[ - float | None, - Doc( - """ - Less than. If set, value must be less than this. Only applicable to numbers. - """ - ), - ] = None, - le: Annotated[ - float | None, - Doc( - """ - Less than or equal. If set, value must be less than or equal to this. - Only applicable to numbers. - """ - ), - ] = None, - min_length: Annotated[ - int | None, - Doc( - """ - Minimum length for strings. - """ - ), - ] = None, - max_length: Annotated[ - int | None, - Doc( - """ - Maximum length for strings. - """ - ), - ] = None, - pattern: Annotated[ - str | None, - Doc( - """ - RegEx pattern for strings. - """ - ), - ] = None, - regex: Annotated[ - str | None, - Doc( - """ - RegEx pattern for strings. - """ - ), - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Annotated[ - str | None, - Doc( - """ - Parameter field name for discriminating the type in a tagged union. - """ - ), - ] = None, - strict: Annotated[ - bool | None, - Doc( - """ - If `True`, strict validation is applied to the field. - """ - ), - ] = _Unset, - multiple_of: Annotated[ - float | None, - Doc( - """ - Value must be a multiple of this. Only applicable to numbers. - """ - ), - ] = _Unset, - allow_inf_nan: Annotated[ - bool | None, - Doc( - """ - Allow `inf`, `-inf`, `nan`. Only applicable to numbers. - """ - ), - ] = _Unset, - max_digits: Annotated[ - int | None, - Doc( - """ - Maximum number of digits allowed for decimal values. - """ - ), - ] = _Unset, - decimal_places: Annotated[ - int | None, - Doc( - """ - Maximum number of decimal places allowed for decimal values. - """ - ), - ] = _Unset, - examples: Annotated[ - list[Any] | None, - Doc( - """ - Example values for this field. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/) - """ - ), - ] = None, - example: Annotated[ - Any | None, - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Annotated[ - dict[str, Example] | None, - Doc( - """ - OpenAPI-specific examples. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Swagger UI (that provides the `/docs` interface) has better support for the - OpenAPI-specific examples than the JSON Schema `examples`, that's the main - use case for this. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). - """ - ), - ] = None, - deprecated: Annotated[ - deprecated | str | bool | None, - Doc( - """ - Mark this parameter field as deprecated. - - It will affect the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - To include (or not) this parameter field in the generated OpenAPI. - You probably don't need it, but it's available. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = True, - json_schema_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Any additional JSON schema data. - """ - ), - ] = None, - **extra: Annotated[ - Any, - Doc( - """ - Include extra fields used by the JSON Schema. - """ - ), - deprecated( - """ - The `extra` kwargs is deprecated. Use `json_schema_extra` instead. - """ - ), - ], -) -> Any: - return params.Form( - default=default, - default_factory=default_factory, - media_type=media_type, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - example=example, - examples=examples, - openapi_examples=openapi_examples, - deprecated=deprecated, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -def File( # noqa: N802 - default: Annotated[ - Any, - Doc( - """ - Default value if the parameter field is not set. - """ - ), - ] = Undefined, - *, - default_factory: Annotated[ - Callable[[], Any] | None, - Doc( - """ - A callable to generate the default value. - - This doesn't affect `Path` parameters as the value is always required. - The parameter is available only for compatibility. - """ - ), - ] = _Unset, - media_type: Annotated[ - str, - Doc( - """ - The media type of this parameter field. Changing it would affect the - generated OpenAPI, but currently it doesn't affect the parsing of the data. - """ - ), - ] = "multipart/form-data", - alias: Annotated[ - str | None, - Doc( - """ - An alternative name for the parameter field. - - This will be used to extract the data and for the generated OpenAPI. - It is particularly useful when you can't use the name you want because it - is a Python reserved keyword or similar. - """ - ), - ] = None, - alias_priority: Annotated[ - int | None, - Doc( - """ - Priority of the alias. This affects whether an alias generator is used. - """ - ), - ] = _Unset, - validation_alias: Annotated[ - str | AliasPath | AliasChoices | None, - Doc( - """ - 'Whitelist' validation step. The parameter field will be the single one - allowed by the alias or set of aliases defined. - """ - ), - ] = None, - serialization_alias: Annotated[ - str | None, - Doc( - """ - 'Blacklist' validation step. The vanilla parameter field will be the - single one of the alias' or set of aliases' fields and all the other - fields will be ignored at serialization time. - """ - ), - ] = None, - title: Annotated[ - str | None, - Doc( - """ - Human-readable title. - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - Human-readable description. - """ - ), - ] = None, - gt: Annotated[ - float | None, - Doc( - """ - Greater than. If set, value must be greater than this. Only applicable to - numbers. - """ - ), - ] = None, - ge: Annotated[ - float | None, - Doc( - """ - Greater than or equal. If set, value must be greater than or equal to - this. Only applicable to numbers. - """ - ), - ] = None, - lt: Annotated[ - float | None, - Doc( - """ - Less than. If set, value must be less than this. Only applicable to numbers. - """ - ), - ] = None, - le: Annotated[ - float | None, - Doc( - """ - Less than or equal. If set, value must be less than or equal to this. - Only applicable to numbers. - """ - ), - ] = None, - min_length: Annotated[ - int | None, - Doc( - """ - Minimum length for strings. - """ - ), - ] = None, - max_length: Annotated[ - int | None, - Doc( - """ - Maximum length for strings. - """ - ), - ] = None, - pattern: Annotated[ - str | None, - Doc( - """ - RegEx pattern for strings. - """ - ), - ] = None, - regex: Annotated[ - str | None, - Doc( - """ - RegEx pattern for strings. - """ - ), - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Annotated[ - str | None, - Doc( - """ - Parameter field name for discriminating the type in a tagged union. - """ - ), - ] = None, - strict: Annotated[ - bool | None, - Doc( - """ - If `True`, strict validation is applied to the field. - """ - ), - ] = _Unset, - multiple_of: Annotated[ - float | None, - Doc( - """ - Value must be a multiple of this. Only applicable to numbers. - """ - ), - ] = _Unset, - allow_inf_nan: Annotated[ - bool | None, - Doc( - """ - Allow `inf`, `-inf`, `nan`. Only applicable to numbers. - """ - ), - ] = _Unset, - max_digits: Annotated[ - int | None, - Doc( - """ - Maximum number of digits allowed for decimal values. - """ - ), - ] = _Unset, - decimal_places: Annotated[ - int | None, - Doc( - """ - Maximum number of decimal places allowed for decimal values. - """ - ), - ] = _Unset, - examples: Annotated[ - list[Any] | None, - Doc( - """ - Example values for this field. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/) - """ - ), - ] = None, - example: Annotated[ - Any | None, - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Annotated[ - dict[str, Example] | None, - Doc( - """ - OpenAPI-specific examples. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Swagger UI (that provides the `/docs` interface) has better support for the - OpenAPI-specific examples than the JSON Schema `examples`, that's the main - use case for this. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). - """ - ), - ] = None, - deprecated: Annotated[ - deprecated | str | bool | None, - Doc( - """ - Mark this parameter field as deprecated. - - It will affect the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - To include (or not) this parameter field in the generated OpenAPI. - You probably don't need it, but it's available. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = True, - json_schema_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Any additional JSON schema data. - """ - ), - ] = None, - **extra: Annotated[ - Any, - Doc( - """ - Include extra fields used by the JSON Schema. - """ - ), - deprecated( - """ - The `extra` kwargs is deprecated. Use `json_schema_extra` instead. - """ - ), - ], -) -> Any: - return params.File( - default=default, - default_factory=default_factory, - media_type=media_type, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - example=example, - examples=examples, - openapi_examples=openapi_examples, - deprecated=deprecated, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -def Depends( # noqa: N802 - dependency: Annotated[ - Callable[..., Any] | None, - Doc( - """ - A "dependable" callable (like a function). - - Don't call it directly, FastAPI will call it for you, just pass the object - directly. - - Read more about it in the - [FastAPI docs for Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/) - """ - ), - ] = None, - *, - use_cache: Annotated[ - bool, - Doc( - """ - By default, after a dependency is called the first time in a request, if - the dependency is declared again for the rest of the request (for example - if the dependency is needed by several dependencies), the value will be - re-used for the rest of the request. - - Set `use_cache` to `False` to disable this behavior and ensure the - dependency is called again (if declared more than once) in the same request. - - Read more about it in the - [FastAPI docs about sub-dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/sub-dependencies/#using-the-same-dependency-multiple-times) - """ - ), - ] = True, - scope: Annotated[ - Literal["function", "request"] | None, - Doc( - """ - Mainly for dependencies with `yield`, define when the dependency function - should start (the code before `yield`) and when it should end (the code - after `yield`). - - * `"function"`: start the dependency before the *path operation function* - that handles the request, end the dependency after the *path operation - function* ends, but **before** the response is sent back to the client. - So, the dependency function will be executed **around** the *path operation - **function***. - * `"request"`: start the dependency before the *path operation function* - that handles the request (similar to when using `"function"`), but end - **after** the response is sent back to the client. So, the dependency - function will be executed **around** the **request** and response cycle. - - Read more about it in the - [FastAPI docs for FastAPI Dependencies with yield](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#early-exit-and-scope) - """ - ), - ] = None, -) -> Any: - """ - Declare a FastAPI dependency. - - It takes a single "dependable" callable (like a function). - - Don't call it directly, FastAPI will call it for you. - - Read more about it in the - [FastAPI docs for Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/). - - **Example** - - ```python - from typing import Annotated - - from fastapi import Depends, FastAPI - - app = FastAPI() - - - async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100): - return {"q": q, "skip": skip, "limit": limit} - - - @app.get("/items/") - async def read_items(commons: Annotated[dict, Depends(common_parameters)]): - return commons - ``` - """ - return params.Depends(dependency=dependency, use_cache=use_cache, scope=scope) - - -def Security( # noqa: N802 - dependency: Annotated[ - Callable[..., Any] | None, - Doc( - """ - A "dependable" callable (like a function). - - Don't call it directly, FastAPI will call it for you, just pass the object - directly. - - Read more about it in the - [FastAPI docs for Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/) - """ - ), - ] = None, - *, - scopes: Annotated[ - Sequence[str] | None, - Doc( - """ - OAuth2 scopes required for the *path operation* that uses this Security - dependency. - - The term "scope" comes from the OAuth2 specification, it seems to be - intentionally vague and interpretable. It normally refers to permissions, - in cases to roles. - - These scopes are integrated with OpenAPI (and the API docs at `/docs`). - So they are visible in the OpenAPI specification. - - Read more about it in the - [FastAPI docs about OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/) - """ - ), - ] = None, - use_cache: Annotated[ - bool, - Doc( - """ - By default, after a dependency is called the first time in a request, if - the dependency is declared again for the rest of the request (for example - if the dependency is needed by several dependencies), the value will be - re-used for the rest of the request. - - Set `use_cache` to `False` to disable this behavior and ensure the - dependency is called again (if declared more than once) in the same request. - - Read more about it in the - [FastAPI docs about sub-dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/sub-dependencies/#using-the-same-dependency-multiple-times) - """ - ), - ] = True, -) -> Any: - """ - Declare a FastAPI Security dependency. - - The only difference with a regular dependency is that it can declare OAuth2 - scopes that will be integrated with OpenAPI and the automatic UI docs (by default - at `/docs`). - - It takes a single "dependable" callable (like a function). - - Don't call it directly, FastAPI will call it for you. - - Read more about it in the - [FastAPI docs for Security](https://fastapi.tiangolo.com/tutorial/security/) and - in the - [FastAPI docs for OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/). - - **Example** - - ```python - from typing import Annotated - - from fastapi import Security, FastAPI - - from .db import User - from .security import get_current_active_user - - app = FastAPI() - - @app.get("/users/me/items/") - async def read_own_items( - current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])] - ): - return [{"item_id": "Foo", "owner": current_user.username}] - ``` - """ - return params.Security(dependency=dependency, scopes=scopes, use_cache=use_cache) diff --git a/server/venv/Lib/site-packages/fastapi/params.py b/server/venv/Lib/site-packages/fastapi/params.py deleted file mode 100644 index d3f2ae1..0000000 --- a/server/venv/Lib/site-packages/fastapi/params.py +++ /dev/null @@ -1,754 +0,0 @@ -import warnings -from collections.abc import Callable, Sequence -from dataclasses import dataclass -from enum import Enum -from typing import Annotated, Any, Literal - -from fastapi.exceptions import FastAPIDeprecationWarning -from fastapi.openapi.models import Example -from pydantic import AliasChoices, AliasPath -from pydantic.fields import FieldInfo -from typing_extensions import deprecated - -from ._compat import ( - Undefined, -) -from .datastructures import _Unset - - -class ParamTypes(Enum): - query = "query" - header = "header" - path = "path" - cookie = "cookie" - - -class Param(FieldInfo): # type: ignore[misc] # ty: ignore[subclass-of-final-class] - in_: ParamTypes - - def __init__( - self, - default: Any = Undefined, - *, - default_factory: Callable[[], Any] | None = _Unset, - annotation: Any | None = None, - alias: str | None = None, - alias_priority: int | None = _Unset, - validation_alias: str | AliasPath | AliasChoices | None = None, - serialization_alias: str | None = None, - title: str | None = None, - description: str | None = None, - gt: float | None = None, - ge: float | None = None, - lt: float | None = None, - le: float | None = None, - min_length: int | None = None, - max_length: int | None = None, - pattern: str | None = None, - regex: Annotated[ - str | None, - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: str | None = None, - strict: bool | None = _Unset, - multiple_of: float | None = _Unset, - allow_inf_nan: bool | None = _Unset, - max_digits: int | None = _Unset, - decimal_places: int | None = _Unset, - examples: list[Any] | None = None, - example: Annotated[ - Any | None, - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: dict[str, Example] | None = None, - deprecated: deprecated | str | bool | None = None, - include_in_schema: bool = True, - json_schema_extra: dict[str, Any] | None = None, - **extra: Any, - ): - if example is not _Unset: - warnings.warn( - "`example` has been deprecated, please use `examples` instead", - category=FastAPIDeprecationWarning, - stacklevel=4, - ) - self.example = example - self.include_in_schema = include_in_schema - self.openapi_examples = openapi_examples - kwargs = dict( - default=default, - default_factory=default_factory, - alias=alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - discriminator=discriminator, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - **extra, - ) - if examples is not None: - kwargs["examples"] = examples - if regex is not None: - warnings.warn( - "`regex` has been deprecated, please use `pattern` instead", - category=FastAPIDeprecationWarning, - stacklevel=4, - ) - current_json_schema_extra = json_schema_extra or extra - kwargs["deprecated"] = deprecated - - if serialization_alias in (_Unset, None) and isinstance(alias, str): - serialization_alias = alias - if validation_alias in (_Unset, None): - validation_alias = alias - kwargs.update( - { - "annotation": annotation, - "alias_priority": alias_priority, - "validation_alias": validation_alias, - "serialization_alias": serialization_alias, - "strict": strict, - "json_schema_extra": current_json_schema_extra, - } - ) - kwargs["pattern"] = pattern or regex - - use_kwargs = {k: v for k, v in kwargs.items() if v is not _Unset} - - super().__init__(**use_kwargs) # ty: ignore[invalid-argument-type] - - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self.default})" - - -class Path(Param): # type: ignore[misc] - in_ = ParamTypes.path - - def __init__( - self, - default: Any = ..., - *, - default_factory: Callable[[], Any] | None = _Unset, - annotation: Any | None = None, - alias: str | None = None, - alias_priority: int | None = _Unset, - validation_alias: str | AliasPath | AliasChoices | None = None, - serialization_alias: str | None = None, - title: str | None = None, - description: str | None = None, - gt: float | None = None, - ge: float | None = None, - lt: float | None = None, - le: float | None = None, - min_length: int | None = None, - max_length: int | None = None, - pattern: str | None = None, - regex: Annotated[ - str | None, - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: str | None = None, - strict: bool | None = _Unset, - multiple_of: float | None = _Unset, - allow_inf_nan: bool | None = _Unset, - max_digits: int | None = _Unset, - decimal_places: int | None = _Unset, - examples: list[Any] | None = None, - example: Annotated[ - Any | None, - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: dict[str, Example] | None = None, - deprecated: deprecated | str | bool | None = None, - include_in_schema: bool = True, - json_schema_extra: dict[str, Any] | None = None, - **extra: Any, - ): - assert default is ..., "Path parameters cannot have a default value" - self.in_ = self.in_ - super().__init__( - default=default, - default_factory=default_factory, - annotation=annotation, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - deprecated=deprecated, - example=example, - examples=examples, - openapi_examples=openapi_examples, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -class Query(Param): # type: ignore[misc] - in_ = ParamTypes.query - - def __init__( - self, - default: Any = Undefined, - *, - default_factory: Callable[[], Any] | None = _Unset, - annotation: Any | None = None, - alias: str | None = None, - alias_priority: int | None = _Unset, - validation_alias: str | AliasPath | AliasChoices | None = None, - serialization_alias: str | None = None, - title: str | None = None, - description: str | None = None, - gt: float | None = None, - ge: float | None = None, - lt: float | None = None, - le: float | None = None, - min_length: int | None = None, - max_length: int | None = None, - pattern: str | None = None, - regex: Annotated[ - str | None, - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: str | None = None, - strict: bool | None = _Unset, - multiple_of: float | None = _Unset, - allow_inf_nan: bool | None = _Unset, - max_digits: int | None = _Unset, - decimal_places: int | None = _Unset, - examples: list[Any] | None = None, - example: Annotated[ - Any | None, - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: dict[str, Example] | None = None, - deprecated: deprecated | str | bool | None = None, - include_in_schema: bool = True, - json_schema_extra: dict[str, Any] | None = None, - **extra: Any, - ): - super().__init__( - default=default, - default_factory=default_factory, - annotation=annotation, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - deprecated=deprecated, - example=example, - examples=examples, - openapi_examples=openapi_examples, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -class Header(Param): # type: ignore[misc] - in_ = ParamTypes.header - - def __init__( - self, - default: Any = Undefined, - *, - default_factory: Callable[[], Any] | None = _Unset, - annotation: Any | None = None, - alias: str | None = None, - alias_priority: int | None = _Unset, - validation_alias: str | AliasPath | AliasChoices | None = None, - serialization_alias: str | None = None, - convert_underscores: bool = True, - title: str | None = None, - description: str | None = None, - gt: float | None = None, - ge: float | None = None, - lt: float | None = None, - le: float | None = None, - min_length: int | None = None, - max_length: int | None = None, - pattern: str | None = None, - regex: Annotated[ - str | None, - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: str | None = None, - strict: bool | None = _Unset, - multiple_of: float | None = _Unset, - allow_inf_nan: bool | None = _Unset, - max_digits: int | None = _Unset, - decimal_places: int | None = _Unset, - examples: list[Any] | None = None, - example: Annotated[ - Any | None, - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: dict[str, Example] | None = None, - deprecated: deprecated | str | bool | None = None, - include_in_schema: bool = True, - json_schema_extra: dict[str, Any] | None = None, - **extra: Any, - ): - self.convert_underscores = convert_underscores - super().__init__( - default=default, - default_factory=default_factory, - annotation=annotation, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - deprecated=deprecated, - example=example, - examples=examples, - openapi_examples=openapi_examples, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -class Cookie(Param): # type: ignore[misc] - in_ = ParamTypes.cookie - - def __init__( - self, - default: Any = Undefined, - *, - default_factory: Callable[[], Any] | None = _Unset, - annotation: Any | None = None, - alias: str | None = None, - alias_priority: int | None = _Unset, - validation_alias: str | AliasPath | AliasChoices | None = None, - serialization_alias: str | None = None, - title: str | None = None, - description: str | None = None, - gt: float | None = None, - ge: float | None = None, - lt: float | None = None, - le: float | None = None, - min_length: int | None = None, - max_length: int | None = None, - pattern: str | None = None, - regex: Annotated[ - str | None, - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: str | None = None, - strict: bool | None = _Unset, - multiple_of: float | None = _Unset, - allow_inf_nan: bool | None = _Unset, - max_digits: int | None = _Unset, - decimal_places: int | None = _Unset, - examples: list[Any] | None = None, - example: Annotated[ - Any | None, - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: dict[str, Example] | None = None, - deprecated: deprecated | str | bool | None = None, - include_in_schema: bool = True, - json_schema_extra: dict[str, Any] | None = None, - **extra: Any, - ): - super().__init__( - default=default, - default_factory=default_factory, - annotation=annotation, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - deprecated=deprecated, - example=example, - examples=examples, - openapi_examples=openapi_examples, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -class Body(FieldInfo): # type: ignore[misc] # ty: ignore[subclass-of-final-class] - def __init__( - self, - default: Any = Undefined, - *, - default_factory: Callable[[], Any] | None = _Unset, - annotation: Any | None = None, - embed: bool | None = None, - media_type: str = "application/json", - alias: str | None = None, - alias_priority: int | None = _Unset, - validation_alias: str | AliasPath | AliasChoices | None = None, - serialization_alias: str | None = None, - title: str | None = None, - description: str | None = None, - gt: float | None = None, - ge: float | None = None, - lt: float | None = None, - le: float | None = None, - min_length: int | None = None, - max_length: int | None = None, - pattern: str | None = None, - regex: Annotated[ - str | None, - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: str | None = None, - strict: bool | None = _Unset, - multiple_of: float | None = _Unset, - allow_inf_nan: bool | None = _Unset, - max_digits: int | None = _Unset, - decimal_places: int | None = _Unset, - examples: list[Any] | None = None, - example: Annotated[ - Any | None, - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: dict[str, Example] | None = None, - deprecated: deprecated | str | bool | None = None, - include_in_schema: bool = True, - json_schema_extra: dict[str, Any] | None = None, - **extra: Any, - ): - self.embed = embed - self.media_type = media_type - if example is not _Unset: - warnings.warn( - "`example` has been deprecated, please use `examples` instead", - category=FastAPIDeprecationWarning, - stacklevel=4, - ) - self.example = example - self.include_in_schema = include_in_schema - self.openapi_examples = openapi_examples - kwargs = dict( - default=default, - default_factory=default_factory, - alias=alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - discriminator=discriminator, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - **extra, - ) - if examples is not None: - kwargs["examples"] = examples - if regex is not None: - warnings.warn( - "`regex` has been deprecated, please use `pattern` instead", - category=FastAPIDeprecationWarning, - stacklevel=4, - ) - current_json_schema_extra = json_schema_extra or extra - kwargs["deprecated"] = deprecated - if serialization_alias in (_Unset, None) and isinstance(alias, str): - serialization_alias = alias - if validation_alias in (_Unset, None): - validation_alias = alias - kwargs.update( - { - "annotation": annotation, - "alias_priority": alias_priority, - "validation_alias": validation_alias, - "serialization_alias": serialization_alias, - "strict": strict, - "json_schema_extra": current_json_schema_extra, - } - ) - kwargs["pattern"] = pattern or regex - - use_kwargs = {k: v for k, v in kwargs.items() if v is not _Unset} - - super().__init__(**use_kwargs) # ty: ignore[invalid-argument-type] - - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self.default})" - - -class Form(Body): # type: ignore[misc] - def __init__( - self, - default: Any = Undefined, - *, - default_factory: Callable[[], Any] | None = _Unset, - annotation: Any | None = None, - media_type: str = "application/x-www-form-urlencoded", - alias: str | None = None, - alias_priority: int | None = _Unset, - validation_alias: str | AliasPath | AliasChoices | None = None, - serialization_alias: str | None = None, - title: str | None = None, - description: str | None = None, - gt: float | None = None, - ge: float | None = None, - lt: float | None = None, - le: float | None = None, - min_length: int | None = None, - max_length: int | None = None, - pattern: str | None = None, - regex: Annotated[ - str | None, - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: str | None = None, - strict: bool | None = _Unset, - multiple_of: float | None = _Unset, - allow_inf_nan: bool | None = _Unset, - max_digits: int | None = _Unset, - decimal_places: int | None = _Unset, - examples: list[Any] | None = None, - example: Annotated[ - Any | None, - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: dict[str, Example] | None = None, - deprecated: deprecated | str | bool | None = None, - include_in_schema: bool = True, - json_schema_extra: dict[str, Any] | None = None, - **extra: Any, - ): - super().__init__( - default=default, - default_factory=default_factory, - annotation=annotation, - media_type=media_type, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - deprecated=deprecated, - example=example, - examples=examples, - openapi_examples=openapi_examples, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -class File(Form): # type: ignore[misc] - def __init__( - self, - default: Any = Undefined, - *, - default_factory: Callable[[], Any] | None = _Unset, - annotation: Any | None = None, - media_type: str = "multipart/form-data", - alias: str | None = None, - alias_priority: int | None = _Unset, - validation_alias: str | AliasPath | AliasChoices | None = None, - serialization_alias: str | None = None, - title: str | None = None, - description: str | None = None, - gt: float | None = None, - ge: float | None = None, - lt: float | None = None, - le: float | None = None, - min_length: int | None = None, - max_length: int | None = None, - pattern: str | None = None, - regex: Annotated[ - str | None, - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: str | None = None, - strict: bool | None = _Unset, - multiple_of: float | None = _Unset, - allow_inf_nan: bool | None = _Unset, - max_digits: int | None = _Unset, - decimal_places: int | None = _Unset, - examples: list[Any] | None = None, - example: Annotated[ - Any | None, - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: dict[str, Example] | None = None, - deprecated: deprecated | str | bool | None = None, - include_in_schema: bool = True, - json_schema_extra: dict[str, Any] | None = None, - **extra: Any, - ): - super().__init__( - default=default, - default_factory=default_factory, - annotation=annotation, - media_type=media_type, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - deprecated=deprecated, - example=example, - examples=examples, - openapi_examples=openapi_examples, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -@dataclass(frozen=True) -class Depends: - dependency: Callable[..., Any] | None = None - use_cache: bool = True - scope: Literal["function", "request"] | None = None - - -@dataclass(frozen=True) -class Security(Depends): - scopes: Sequence[str] | None = None diff --git a/server/venv/Lib/site-packages/fastapi/py.typed b/server/venv/Lib/site-packages/fastapi/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/server/venv/Lib/site-packages/fastapi/requests.py b/server/venv/Lib/site-packages/fastapi/requests.py deleted file mode 100644 index d16552c..0000000 --- a/server/venv/Lib/site-packages/fastapi/requests.py +++ /dev/null @@ -1,2 +0,0 @@ -from starlette.requests import HTTPConnection as HTTPConnection # noqa: F401 -from starlette.requests import Request as Request # noqa: F401 diff --git a/server/venv/Lib/site-packages/fastapi/responses.py b/server/venv/Lib/site-packages/fastapi/responses.py deleted file mode 100644 index 29df4b7..0000000 --- a/server/venv/Lib/site-packages/fastapi/responses.py +++ /dev/null @@ -1,98 +0,0 @@ -import importlib -from typing import Any, Protocol, cast - -from fastapi.exceptions import FastAPIDeprecationWarning -from fastapi.sse import EventSourceResponse as EventSourceResponse # noqa -from starlette.responses import FileResponse as FileResponse # noqa -from starlette.responses import HTMLResponse as HTMLResponse # noqa -from starlette.responses import JSONResponse as JSONResponse # noqa -from starlette.responses import PlainTextResponse as PlainTextResponse # noqa -from starlette.responses import RedirectResponse as RedirectResponse # noqa -from starlette.responses import Response as Response # noqa -from starlette.responses import StreamingResponse as StreamingResponse # noqa -from typing_extensions import deprecated - - -class _UjsonModule(Protocol): - def dumps(self, __obj: Any, *, ensure_ascii: bool = ...) -> str: ... - - -class _OrjsonModule(Protocol): - OPT_NON_STR_KEYS: int - OPT_SERIALIZE_NUMPY: int - - def dumps(self, __obj: Any, *, option: int = ...) -> bytes: ... - - -try: - ujson = cast(_UjsonModule, importlib.import_module("ujson")) -except ModuleNotFoundError: # pragma: nocover - ujson = None # type: ignore[assignment] - - -try: - orjson = cast(_OrjsonModule, importlib.import_module("orjson")) -except ModuleNotFoundError: # pragma: nocover - orjson = None # type: ignore[assignment] - - -@deprecated( - "UJSONResponse is deprecated, FastAPI now serializes data directly to JSON " - "bytes via Pydantic when a return type or response model is set, which is " - "faster and doesn't need a custom response class. Read more in the FastAPI " - "docs: https://fastapi.tiangolo.com/advanced/custom-response/#orjson-or-response-model " - "and https://fastapi.tiangolo.com/tutorial/response-model/", - category=FastAPIDeprecationWarning, - stacklevel=2, -) -class UJSONResponse(JSONResponse): - """JSON response using the ujson library to serialize data to JSON. - - **Deprecated**: `UJSONResponse` is deprecated. FastAPI now serializes data - directly to JSON bytes via Pydantic when a return type or response model is - set, which is faster and doesn't need a custom response class. - - Read more in the - [FastAPI docs for Custom Response](https://fastapi.tiangolo.com/advanced/custom-response/#orjson-or-response-model) - and the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - - **Note**: `ujson` is not included with FastAPI and must be installed - separately, e.g. `pip install ujson`. - """ - - def render(self, content: Any) -> bytes: - assert ujson is not None, "ujson must be installed to use UJSONResponse" - return ujson.dumps(content, ensure_ascii=False).encode("utf-8") - - -@deprecated( - "ORJSONResponse is deprecated, FastAPI now serializes data directly to JSON " - "bytes via Pydantic when a return type or response model is set, which is " - "faster and doesn't need a custom response class. Read more in the FastAPI " - "docs: https://fastapi.tiangolo.com/advanced/custom-response/#orjson-or-response-model " - "and https://fastapi.tiangolo.com/tutorial/response-model/", - category=FastAPIDeprecationWarning, - stacklevel=2, -) -class ORJSONResponse(JSONResponse): - """JSON response using the orjson library to serialize data to JSON. - - **Deprecated**: `ORJSONResponse` is deprecated. FastAPI now serializes data - directly to JSON bytes via Pydantic when a return type or response model is - set, which is faster and doesn't need a custom response class. - - Read more in the - [FastAPI docs for Custom Response](https://fastapi.tiangolo.com/advanced/custom-response/#orjson-or-response-model) - and the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - - **Note**: `orjson` is not included with FastAPI and must be installed - separately, e.g. `pip install orjson`. - """ - - def render(self, content: Any) -> bytes: - assert orjson is not None, "orjson must be installed to use ORJSONResponse" - return orjson.dumps( - content, option=orjson.OPT_NON_STR_KEYS | orjson.OPT_SERIALIZE_NUMPY - ) diff --git a/server/venv/Lib/site-packages/fastapi/routing.py b/server/venv/Lib/site-packages/fastapi/routing.py deleted file mode 100644 index 3a2d754..0000000 --- a/server/venv/Lib/site-packages/fastapi/routing.py +++ /dev/null @@ -1,6231 +0,0 @@ -import contextlib -import copy -import email.message -import errno -import functools -import inspect -import json -import os -import stat -import types -from collections.abc import ( - AsyncIterator, - Awaitable, - Callable, - Collection, - Coroutine, - Generator, - Iterator, - Mapping, - Sequence, -) -from contextlib import ( - AbstractAsyncContextManager, - AbstractContextManager, - AsyncExitStack, - asynccontextmanager, -) -from contextvars import ContextVar -from dataclasses import dataclass, field -from enum import Enum, IntEnum -from typing import ( - Annotated, - Any, - Literal, - Protocol, - TypeVar, - cast, -) - -import anyio -from annotated_doc import Doc -from anyio.abc import ObjectReceiveStream -from fastapi import params -from fastapi._compat import ( - ModelField, - Undefined, - lenient_issubclass, -) -from fastapi.datastructures import Default, DefaultPlaceholder -from fastapi.dependencies.models import Dependant -from fastapi.dependencies.utils import ( - _should_embed_body_fields, - get_body_field, - get_dependant, - get_flat_dependant, - get_parameterless_sub_dependant, - get_stream_item_type, - get_typed_return_annotation, - solve_dependencies, -) -from fastapi.encoders import jsonable_encoder -from fastapi.exceptions import ( - EndpointContext, - FastAPIError, - RequestValidationError, - ResponseValidationError, - WebSocketRequestValidationError, -) -from fastapi.sse import ( - _PING_INTERVAL, - KEEPALIVE_COMMENT, - EventSourceResponse, - ServerSentEvent, - format_sse_event, -) -from fastapi.types import DecoratedCallable, IncEx -from fastapi.utils import ( - create_model_field, - generate_unique_id, - get_value_or_default, - is_body_allowed_for_status_code, -) -from starlette import routing -from starlette._exception_handler import wrap_app_handling_exceptions -from starlette._utils import get_route_path, is_async_callable -from starlette.concurrency import iterate_in_threadpool, run_in_threadpool -from starlette.datastructures import URL, FormData, URLPath -from starlette.exceptions import HTTPException -from starlette.requests import Request -from starlette.responses import ( - JSONResponse, - PlainTextResponse, - RedirectResponse, - Response, - StreamingResponse, -) -from starlette.routing import ( - BaseRoute, - Match, - NoMatchFound, - compile_path, - get_name, -) -from starlette.routing import Mount as Mount # noqa -from starlette.staticfiles import StaticFiles -from starlette.types import AppType, ASGIApp, Lifespan, Receive, Scope, Send -from starlette.websockets import WebSocket -from typing_extensions import deprecated - - -# Copy of starlette.routing.request_response modified to include the -# dependencies' AsyncExitStack -def request_response( - func: Callable[[Request], Awaitable[Response] | Response], -) -> ASGIApp: - """ - Takes a function or coroutine `func(request) -> response`, - and returns an ASGI application. - """ - f: Callable[[Request], Awaitable[Response]] = ( - func # type: ignore[assignment] - if is_async_callable(func) - else functools.partial(run_in_threadpool, func) # type: ignore[call-arg] - ) # ty: ignore[invalid-assignment] - - async def app(scope: Scope, receive: Receive, send: Send) -> None: - request = Request(scope, receive, send) - - async def app(scope: Scope, receive: Receive, send: Send) -> None: - # Starts customization - response_awaited = False - async with AsyncExitStack() as request_stack: - scope["fastapi_inner_astack"] = request_stack - async with AsyncExitStack() as function_stack: - scope["fastapi_function_astack"] = function_stack - response = await f(request) - await response(scope, receive, send) - # Continues customization - response_awaited = True - if not response_awaited: - raise FastAPIError( - "Response not awaited. There's a high chance that the " - "application code is raising an exception and a dependency with yield " - "has a block with a bare except, or a block with except Exception, " - "and is not raising the exception again. Read more about it in the " - "docs: https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#dependencies-with-yield-and-except" - ) - - # Same as in Starlette - await wrap_app_handling_exceptions(app, request)(scope, receive, send) - - return app - - -# Copy of starlette.routing.websocket_session modified to include the -# dependencies' AsyncExitStack -def websocket_session( - func: Callable[[WebSocket], Awaitable[None]], -) -> ASGIApp: - """ - Takes a coroutine `func(session)`, and returns an ASGI application. - """ - # assert asyncio.iscoroutinefunction(func), "WebSocket endpoints must be async" - - async def app(scope: Scope, receive: Receive, send: Send) -> None: - session = WebSocket(scope, receive=receive, send=send) - - async def app(scope: Scope, receive: Receive, send: Send) -> None: - async with AsyncExitStack() as request_stack: - scope["fastapi_inner_astack"] = request_stack - async with AsyncExitStack() as function_stack: - scope["fastapi_function_astack"] = function_stack - await func(session) - - # Same as in Starlette - await wrap_app_handling_exceptions(app, session)(scope, receive, send) - - return app - - -_T = TypeVar("_T") - - -# Vendored from starlette.routing to avoid importing private symbols -class _AsyncLiftContextManager(AbstractAsyncContextManager[_T]): - """ - Wraps a synchronous context manager to make it async. - - This is vendored from Starlette to avoid importing private symbols. - """ - - def __init__(self, cm: AbstractContextManager[_T]) -> None: - self._cm = cm - - async def __aenter__(self) -> _T: - return self._cm.__enter__() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - traceback: types.TracebackType | None, - ) -> bool | None: - return self._cm.__exit__(exc_type, exc_value, traceback) - - -# Vendored from starlette.routing to avoid importing private symbols -def _wrap_gen_lifespan_context( - lifespan_context: Callable[[Any], Generator[Any, Any, Any]], -) -> Callable[[Any], AbstractAsyncContextManager[Any]]: - """ - Wrap a generator-based lifespan context into an async context manager. - - This is vendored from Starlette to avoid importing private symbols. - """ - cmgr = contextlib.contextmanager(lifespan_context) - - @functools.wraps(cmgr) - def wrapper(app: Any) -> _AsyncLiftContextManager[Any]: - return _AsyncLiftContextManager(cmgr(app)) - - return wrapper - - -def _merge_lifespan_context( - original_context: Lifespan[Any], nested_context: Lifespan[Any] -) -> Lifespan[Any]: - @asynccontextmanager - async def merged_lifespan( - app: AppType, - ) -> AsyncIterator[Mapping[str, Any] | None]: - async with original_context(app) as maybe_original_state: - async with nested_context(app) as maybe_nested_state: - if maybe_nested_state is None and maybe_original_state is None: - yield None # old ASGI compatibility - else: - yield {**(maybe_nested_state or {}), **(maybe_original_state or {})} - - return merged_lifespan # type: ignore[return-value] # ty: ignore[invalid-return-type] - - -class _DefaultLifespan: - """ - Default lifespan context manager that runs on_startup and on_shutdown handlers. - - This is a copy of the Starlette _DefaultLifespan class that was removed - in Starlette. FastAPI keeps it to maintain backward compatibility with - on_startup and on_shutdown event handlers. - - Ref: https://github.com/Kludex/starlette/pull/3117 - """ - - def __init__(self, router: "APIRouter") -> None: - self._router = router - - async def __aenter__(self) -> None: - await self._router._startup() - - async def __aexit__(self, *exc_info: object) -> None: - await self._router._shutdown() - - def __call__(self: _T, app: object) -> _T: - return self - - -# Cache for endpoint context to avoid re-extracting on every request -_endpoint_context_cache: dict[int, EndpointContext] = {} - - -def _extract_endpoint_context(func: Any) -> EndpointContext: - """Extract endpoint context with caching to avoid repeated file I/O.""" - func_id = id(func) - - if func_id in _endpoint_context_cache: - return _endpoint_context_cache[func_id] - - try: - ctx: EndpointContext = {} - - if (source_file := inspect.getsourcefile(func)) is not None: - ctx["file"] = source_file - if (line_number := inspect.getsourcelines(func)[1]) is not None: - ctx["line"] = line_number - if (func_name := getattr(func, "__name__", None)) is not None: - ctx["function"] = func_name - except Exception: - ctx = EndpointContext() - - _endpoint_context_cache[func_id] = ctx - return ctx - - -async def serialize_response( - *, - field: ModelField | None = None, - response_content: Any, - include: IncEx | None = None, - exclude: IncEx | None = None, - by_alias: bool = True, - exclude_unset: bool = False, - exclude_defaults: bool = False, - exclude_none: bool = False, - is_coroutine: bool = True, - endpoint_ctx: EndpointContext | None = None, - dump_json: bool = False, -) -> Any: - if field: - if is_coroutine: - value, errors = field.validate(response_content, {}, loc=("response",)) - else: - value, errors = await run_in_threadpool( - field.validate, response_content, {}, loc=("response",) - ) - if errors: - ctx = endpoint_ctx or EndpointContext() - raise ResponseValidationError( - errors=errors, - body=response_content, - endpoint_ctx=ctx, - ) - serializer = field.serialize_json if dump_json else field.serialize - return serializer( - value, - include=include, - exclude=exclude, - by_alias=by_alias, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - ) - - else: - return jsonable_encoder(response_content) - - -async def run_endpoint_function( - *, dependant: Dependant, values: dict[str, Any], is_coroutine: bool -) -> Any: - # Only called by get_request_handler. Has been split into its own function to - # facilitate profiling endpoints, since inner functions are harder to profile. - assert dependant.call is not None, "dependant.call must be a function" - - if is_coroutine: - return await dependant.call(**values) - else: - return await run_in_threadpool(dependant.call, **values) - - -def _build_response_args( - *, status_code: int | None, solved_result: Any -) -> dict[str, Any]: - response_args: dict[str, Any] = { - "background": solved_result.background_tasks, - } - # If status_code was set, use it, otherwise use the default from the - # response class, in the case of redirect it's 307 - current_status_code = ( - status_code if status_code else solved_result.response.status_code - ) - if current_status_code is not None: - response_args["status_code"] = current_status_code - if solved_result.response.status_code: - response_args["status_code"] = solved_result.response.status_code - return response_args - - -def get_request_handler( - dependant: Dependant, - body_field: ModelField | None = None, - status_code: int | None = None, - response_class: type[Response] | DefaultPlaceholder = Default(JSONResponse), - response_field: ModelField | None = None, - response_model_include: IncEx | None = None, - response_model_exclude: IncEx | None = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - dependency_overrides_provider: Any | None = None, - embed_body_fields: bool = False, - strict_content_type: bool | DefaultPlaceholder = Default(True), - stream_item_field: ModelField | None = None, - is_json_stream: bool = False, -) -> Callable[[Request], Coroutine[Any, Any, Response]]: - assert dependant.call is not None, "dependant.call must be a function" - is_coroutine = dependant.is_coroutine_callable - is_body_form = body_field and isinstance(body_field.field_info, params.Form) - if isinstance(response_class, DefaultPlaceholder): - actual_response_class: type[Response] = response_class.value - else: - actual_response_class = response_class - is_sse_stream = lenient_issubclass(actual_response_class, EventSourceResponse) - if isinstance(strict_content_type, DefaultPlaceholder): - actual_strict_content_type: bool = strict_content_type.value - else: - actual_strict_content_type = strict_content_type - - async def app(request: Request) -> Response: - response: Response | None = None - file_stack = request.scope.get("fastapi_middleware_astack") - assert isinstance(file_stack, AsyncExitStack), ( - "fastapi_middleware_astack not found in request scope" - ) - - # Extract endpoint context for error messages - endpoint_ctx = ( - _extract_endpoint_context(dependant.call) - if dependant.call - else EndpointContext() - ) - - if dependant.path: - # For mounted sub-apps, include the mount path prefix - mount_path = request.scope.get("root_path", "").rstrip("/") - endpoint_ctx["path"] = f"{request.method} {mount_path}{dependant.path}" - - # Read body and auto-close files - try: - body: Any = None - if body_field: - if is_body_form: - body = await request.form() - file_stack.push_async_callback(body.close) - else: - body_bytes = await request.body() - if body_bytes: - json_body: Any = Undefined - content_type_value = request.headers.get("content-type") - if not content_type_value: - if not actual_strict_content_type: - json_body = await request.json() - else: - message = email.message.Message() - message["content-type"] = content_type_value - if message.get_content_maintype() == "application": - subtype = message.get_content_subtype() - if subtype == "json" or subtype.endswith("+json"): - json_body = await request.json() - if json_body != Undefined: - body = json_body - else: - body = body_bytes - except json.JSONDecodeError as e: - validation_error = RequestValidationError( - [ - { - "type": "json_invalid", - "loc": ("body", e.pos), - "msg": "JSON decode error", - "input": {}, - "ctx": {"error": e.msg}, - } - ], - body=e.doc, - endpoint_ctx=endpoint_ctx, - ) - raise validation_error from e - except HTTPException: - # If a middleware raises an HTTPException, it should be raised again - raise - except Exception as e: - http_error = HTTPException( - status_code=400, detail="There was an error parsing the body" - ) - raise http_error from e - - # Solve dependencies and run path operation function, auto-closing dependencies - errors: list[Any] = [] - async_exit_stack = request.scope.get("fastapi_inner_astack") - assert isinstance(async_exit_stack, AsyncExitStack), ( - "fastapi_inner_astack not found in request scope" - ) - solved_result = await solve_dependencies( - request=request, - dependant=dependant, - body=cast(dict[str, Any] | FormData | bytes | None, body), - dependency_overrides_provider=dependency_overrides_provider, - async_exit_stack=async_exit_stack, - embed_body_fields=embed_body_fields, - ) - errors = solved_result.errors - assert dependant.call # For types - if not errors: - # Shared serializer for stream items (JSONL and SSE). - # Validates against stream_item_field when set, then - # serializes to JSON bytes. - def _serialize_data(data: Any) -> bytes: - if stream_item_field: - value, errors_ = stream_item_field.validate( - data, {}, loc=("response",) - ) - if errors_: - ctx = endpoint_ctx or EndpointContext() - raise ResponseValidationError( - errors=errors_, - body=data, - endpoint_ctx=ctx, - ) - return stream_item_field.serialize_json( - value, - include=response_model_include, - exclude=response_model_exclude, - by_alias=response_model_by_alias, - exclude_unset=response_model_exclude_unset, - exclude_defaults=response_model_exclude_defaults, - exclude_none=response_model_exclude_none, - ) - else: - data = jsonable_encoder(data) - return json.dumps(data).encode("utf-8") - - if is_sse_stream: - # Generator endpoint: stream as Server-Sent Events - gen = dependant.call(**solved_result.values) - - def _serialize_sse_item(item: Any) -> bytes: - if isinstance(item, ServerSentEvent): - # User controls the event structure. - # Serialize the data payload if present. - # For ServerSentEvent items we skip stream_item_field - # validation (the user may mix types intentionally). - if item.raw_data is not None: - data_str: str | None = item.raw_data - elif item.data is not None: - if hasattr(item.data, "model_dump_json"): - data_str = item.data.model_dump_json() - else: - data_str = json.dumps(jsonable_encoder(item.data)) - else: - data_str = None - return format_sse_event( - data_str=data_str, - event=item.event, - id=item.id, - retry=item.retry, - comment=item.comment, - ) - else: - # Plain object: validate + serialize via - # stream_item_field (if set) and wrap in data field - return format_sse_event( - data_str=_serialize_data(item).decode("utf-8") - ) - - if dependant.is_async_gen_callable: - sse_aiter: AsyncIterator[Any] = gen.__aiter__() - else: - sse_aiter = iterate_in_threadpool(gen) - - @asynccontextmanager - async def _sse_producer_cm() -> AsyncIterator[ - ObjectReceiveStream[bytes] - ]: - # Use a memory stream to decouple generator iteration - # from the keepalive timer. A producer task pulls items - # from the generator independently, so - # `anyio.fail_after` never wraps the generator's - # `__anext__` directly - avoiding CancelledError that - # would finalize the generator and also working for sync - # generators running in a thread pool. - # - # This context manager is entered on the request-scoped - # AsyncExitStack so its __aexit__ (which cancels the - # task group) is called by the exit stack after the - # streaming response completes — not by async generator - # finalization via GeneratorExit. - # Ref: https://peps.python.org/pep-0789/ - send_stream, receive_stream = anyio.create_memory_object_stream[ - bytes - ](max_buffer_size=1) - - async def _producer() -> None: - async with send_stream: - async for raw_item in sse_aiter: - await send_stream.send(_serialize_sse_item(raw_item)) - - send_keepalive, receive_keepalive = ( - anyio.create_memory_object_stream[bytes](max_buffer_size=1) - ) - - async def _keepalive_inserter() -> None: - """Read from the producer and forward to the output, - inserting keepalive comments on timeout.""" - async with send_keepalive, receive_stream: - try: - while True: - try: - with anyio.fail_after(_PING_INTERVAL): - data = await receive_stream.receive() - await send_keepalive.send(data) - except TimeoutError: - await send_keepalive.send(KEEPALIVE_COMMENT) - except anyio.EndOfStream: - pass - - async with anyio.create_task_group() as tg: - tg.start_soon(_producer) - tg.start_soon(_keepalive_inserter) - yield receive_keepalive - tg.cancel_scope.cancel() - - # Enter the SSE context manager on the request-scoped - # exit stack. The stack outlives the streaming response, - # so __aexit__ runs via proper structured teardown, not - # via GeneratorExit thrown into an async generator. - sse_receive_stream = await async_exit_stack.enter_async_context( - _sse_producer_cm() - ) - # Ensure the receive stream is closed when the exit stack - # unwinds, preventing ResourceWarning from __del__. - async_exit_stack.push_async_callback(sse_receive_stream.aclose) - - async def _sse_with_checkpoints( - stream: ObjectReceiveStream[bytes], - ) -> AsyncIterator[bytes]: - async for data in stream: - yield data - # Guarantee a checkpoint so cancellation can be - # delivered even when the producer is faster than - # the consumer and receive() never suspends. - await anyio.sleep(0) - - sse_stream_content: AsyncIterator[bytes] | Iterator[bytes] = ( - _sse_with_checkpoints(sse_receive_stream) - ) - - response = StreamingResponse( - sse_stream_content, - media_type="text/event-stream", - background=solved_result.background_tasks, - ) - response.headers["Cache-Control"] = "no-cache" - # For Nginx proxies to not buffer server sent events - response.headers["X-Accel-Buffering"] = "no" - response.headers.raw.extend(solved_result.response.headers.raw) - elif is_json_stream: - # Generator endpoint: stream as JSONL - gen = dependant.call(**solved_result.values) - - def _serialize_item(item: Any) -> bytes: - return _serialize_data(item) + b"\n" - - if dependant.is_async_gen_callable: - - async def _async_stream_jsonl() -> AsyncIterator[bytes]: - async for item in gen: - yield _serialize_item(item) - # To allow for cancellation to trigger - # Ref: https://github.com/fastapi/fastapi/issues/14680 - await anyio.sleep(0) - - jsonl_stream_content: AsyncIterator[bytes] | Iterator[bytes] = ( - _async_stream_jsonl() - ) - else: - - def _sync_stream_jsonl() -> Iterator[bytes]: - for item in gen: # ty: ignore[not-iterable] - yield _serialize_item(item) - - jsonl_stream_content = _sync_stream_jsonl() - - response = StreamingResponse( - jsonl_stream_content, - media_type="application/jsonl", - background=solved_result.background_tasks, - ) - response.headers.raw.extend(solved_result.response.headers.raw) - elif dependant.is_async_gen_callable or dependant.is_gen_callable: - # Raw streaming with explicit response_class (e.g. StreamingResponse) - gen = dependant.call(**solved_result.values) - if dependant.is_async_gen_callable: - - async def _async_stream_raw( - async_gen: AsyncIterator[Any], - ) -> AsyncIterator[Any]: - async for chunk in async_gen: - yield chunk - # To allow for cancellation to trigger - # Ref: https://github.com/fastapi/fastapi/issues/14680 - await anyio.sleep(0) - - gen = _async_stream_raw(gen) - response_args = _build_response_args( - status_code=status_code, solved_result=solved_result - ) - response = actual_response_class(content=gen, **response_args) - response.headers.raw.extend(solved_result.response.headers.raw) - else: - raw_response = await run_endpoint_function( - dependant=dependant, - values=solved_result.values, - is_coroutine=is_coroutine, - ) - if isinstance(raw_response, Response): - if raw_response.background is None: - raw_response.background = solved_result.background_tasks - response = raw_response - else: - response_args = _build_response_args( - status_code=status_code, solved_result=solved_result - ) - # Use the fast path (dump_json) when no custom response - # class was set and a response field with a TypeAdapter - # exists. Serializes directly to JSON bytes via Pydantic's - # Rust core, skipping the intermediate Python dict + - # json.dumps() step. - use_dump_json = response_field is not None and isinstance( - response_class, DefaultPlaceholder - ) - content = await serialize_response( - field=response_field, - response_content=raw_response, - include=response_model_include, - exclude=response_model_exclude, - by_alias=response_model_by_alias, - exclude_unset=response_model_exclude_unset, - exclude_defaults=response_model_exclude_defaults, - exclude_none=response_model_exclude_none, - is_coroutine=is_coroutine, - endpoint_ctx=endpoint_ctx, - dump_json=use_dump_json, - ) - if use_dump_json: - response = Response( - content=content, - media_type="application/json", - **response_args, - ) - else: - response = actual_response_class(content, **response_args) - if not is_body_allowed_for_status_code(response.status_code): - response.body = b"" - response.headers.raw.extend(solved_result.response.headers.raw) - if errors: - validation_error = RequestValidationError( - errors, body=body, endpoint_ctx=endpoint_ctx - ) - raise validation_error - - # Return response - assert response - return response - - return app - - -def get_websocket_app( - dependant: Dependant, - dependency_overrides_provider: Any | None = None, - embed_body_fields: bool = False, -) -> Callable[[WebSocket], Coroutine[Any, Any, Any]]: - async def app(websocket: WebSocket) -> None: - endpoint_ctx = ( - _extract_endpoint_context(dependant.call) - if dependant.call - else EndpointContext() - ) - if dependant.path: - # For mounted sub-apps, include the mount path prefix - mount_path = websocket.scope.get("root_path", "").rstrip("/") - endpoint_ctx["path"] = f"WS {mount_path}{dependant.path}" - async_exit_stack = websocket.scope.get("fastapi_inner_astack") - assert isinstance(async_exit_stack, AsyncExitStack), ( - "fastapi_inner_astack not found in request scope" - ) - solved_result = await solve_dependencies( - request=websocket, - dependant=dependant, - dependency_overrides_provider=dependency_overrides_provider, - async_exit_stack=async_exit_stack, - embed_body_fields=embed_body_fields, - ) - if solved_result.errors: - raise WebSocketRequestValidationError( - solved_result.errors, - endpoint_ctx=endpoint_ctx, - ) - assert dependant.call is not None, "dependant.call must be a function" - await dependant.call(**solved_result.values) - - return app - - -class APIWebSocketRoute(routing.WebSocketRoute): - def __init__( - self, - path: str, - endpoint: Callable[..., Any], - *, - name: str | None = None, - dependencies: Sequence[params.Depends] | None = None, - dependency_overrides_provider: Any | None = None, - ) -> None: - self.path = path - self.endpoint = endpoint - self.name = get_name(endpoint) if name is None else name - self.dependencies = list(dependencies or []) - self.path_regex, self.path_format, self.param_convertors = compile_path(path) - self.dependant = get_dependant( - path=self.path_format, call=self.endpoint, scope="function" - ) - for depends in self.dependencies[::-1]: - self.dependant.dependencies.insert( - 0, - get_parameterless_sub_dependant(depends=depends, path=self.path_format), - ) - self._flat_dependant = get_flat_dependant(self.dependant) - self._embed_body_fields = _should_embed_body_fields( - self._flat_dependant.body_params - ) - self.app = websocket_session( - get_websocket_app( - dependant=self.dependant, - dependency_overrides_provider=dependency_overrides_provider, - embed_body_fields=self._embed_body_fields, - ) - ) - - def matches(self, scope: Scope) -> tuple[Match, Scope]: - match, child_scope = super().matches(scope) - if match != Match.NONE: - child_scope["route"] = self - return match, child_scope - - -_FASTAPI_SCOPE_KEY = "fastapi" -_FASTAPI_EFFECTIVE_ROUTE_CONTEXT_KEY = "effective_route_context" -_FASTAPI_FRONTEND_PATH_KEY = "frontend_path" -_FASTAPI_INCLUDED_ROUTER_KEY = "included_router" -_effective_route_context_var: ContextVar[Any | None] = ContextVar( - "fastapi_effective_route_context", default=None -) -_SCOPE_MISSING = object() - - -class _RouteWithPath(Protocol): - path: str - - -def _get_fastapi_scope(scope: Scope) -> dict[str, Any]: - fastapi_scope = scope.setdefault(_FASTAPI_SCOPE_KEY, {}) - assert isinstance(fastapi_scope, dict) - return fastapi_scope - - -def _update_scope(scope: Scope, child_scope: Scope) -> None: - fastapi_child_scope = child_scope.get(_FASTAPI_SCOPE_KEY) - for key, value in child_scope.items(): - if key != _FASTAPI_SCOPE_KEY: - scope[key] = value - if isinstance(fastapi_child_scope, dict): - _get_fastapi_scope(scope).update(fastapi_child_scope) - - -def _get_scope_effective_route_context(scope: Scope) -> Any | None: - return scope.get(_FASTAPI_SCOPE_KEY, {}).get(_FASTAPI_EFFECTIVE_ROUTE_CONTEXT_KEY) - - -def _get_scope_included_router(scope: Scope) -> Any | None: - return scope.get(_FASTAPI_SCOPE_KEY, {}).get(_FASTAPI_INCLUDED_ROUTER_KEY) - - -def _restore_fastapi_scope_key(scope: Scope, key: str, previous: Any) -> None: - fastapi_scope = scope.get(_FASTAPI_SCOPE_KEY) - if not isinstance(fastapi_scope, dict): - return - if previous is _SCOPE_MISSING: - fastapi_scope.pop(key, None) - else: - fastapi_scope[key] = previous - - -class _APIRouteLike(Protocol): - path: str - endpoint: Callable[..., Any] - stream_item_type: Any | None - response_model: Any - summary: str | None - response_description: str - deprecated: bool | None - operation_id: str | None - response_model_include: IncEx | None - response_model_exclude: IncEx | None - response_model_by_alias: bool - response_model_exclude_unset: bool - response_model_exclude_defaults: bool - response_model_exclude_none: bool - include_in_schema: bool - response_class: type[Response] | DefaultPlaceholder - dependency_overrides_provider: Any | None - callbacks: list[BaseRoute] | None - openapi_extra: dict[str, Any] | None - generate_unique_id_function: Callable[[Any], str] | DefaultPlaceholder - strict_content_type: bool | DefaultPlaceholder - tags: list[str | Enum] - responses: dict[int | str, dict[str, Any]] - name: str - path_regex: Any - path_format: str - param_convertors: dict[str, Any] - methods: set[str] - unique_id: str - status_code: int | None - response_field: ModelField | None - stream_item_field: ModelField | None - dependencies: list[params.Depends] - description: str - response_fields: dict[int | str, ModelField] - dependant: Dependant - _flat_dependant: Dependant - _embed_body_fields: bool - body_field: ModelField | None - is_sse_stream: bool - is_json_stream: bool - - -def _populate_api_route_state( - route: _APIRouteLike, - path: str, - endpoint: Callable[..., Any], - *, - response_model: Any = Default(None), - status_code: int | None = None, - tags: list[str | Enum] | None = None, - dependencies: Sequence[params.Depends] | None = None, - summary: str | None = None, - description: str | None = None, - response_description: str = "Successful Response", - responses: dict[int | str, dict[str, Any]] | None = None, - deprecated: bool | None = None, - name: str | None = None, - methods: set[str] | list[str] | None = None, - operation_id: str | None = None, - response_model_include: IncEx | None = None, - response_model_exclude: IncEx | None = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: type[Response] | DefaultPlaceholder = Default(JSONResponse), - dependency_overrides_provider: Any | None = None, - callbacks: list[BaseRoute] | None = None, - openapi_extra: dict[str, Any] | None = None, - generate_unique_id_function: Callable[[Any], str] | DefaultPlaceholder = Default( - generate_unique_id - ), - strict_content_type: bool | DefaultPlaceholder = Default(True), -) -> None: - route.path = path - route.endpoint = endpoint - route.stream_item_type = None - if isinstance(response_model, DefaultPlaceholder): - return_annotation = get_typed_return_annotation(endpoint) - if lenient_issubclass(return_annotation, Response): - response_model = None - else: - stream_item = get_stream_item_type(return_annotation) - if stream_item is not None: - # Extract item type for JSONL or SSE streaming when - # response_class is DefaultPlaceholder (JSONL) or - # EventSourceResponse (SSE). - # ServerSentEvent is excluded: it's a transport - # wrapper, not a data model, so it shouldn't feed - # into validation or OpenAPI schema generation. - if ( - isinstance(response_class, DefaultPlaceholder) - or lenient_issubclass(response_class, EventSourceResponse) - ) and not lenient_issubclass(stream_item, ServerSentEvent): - route.stream_item_type = stream_item - response_model = None - else: - response_model = return_annotation - route.response_model = response_model - route.summary = summary - route.response_description = response_description - route.deprecated = deprecated - route.operation_id = operation_id - route.response_model_include = response_model_include - route.response_model_exclude = response_model_exclude - route.response_model_by_alias = response_model_by_alias - route.response_model_exclude_unset = response_model_exclude_unset - route.response_model_exclude_defaults = response_model_exclude_defaults - route.response_model_exclude_none = response_model_exclude_none - route.include_in_schema = include_in_schema - route.response_class = response_class - route.dependency_overrides_provider = dependency_overrides_provider - route.callbacks = callbacks - route.openapi_extra = openapi_extra - route.generate_unique_id_function = generate_unique_id_function - route.strict_content_type = strict_content_type - route.tags = tags or [] - route.responses = responses or {} - route.name = get_name(endpoint) if name is None else name - route.path_regex, route.path_format, route.param_convertors = compile_path(path) - if methods is None: - methods = ["GET"] - route.methods = {method.upper() for method in methods} - if isinstance(generate_unique_id_function, DefaultPlaceholder): - current_generate_unique_id: Callable[[Any], str] = ( - generate_unique_id_function.value - ) - else: - current_generate_unique_id = generate_unique_id_function - route.unique_id = route.operation_id or current_generate_unique_id(route) - # normalize enums e.g. http.HTTPStatus - if isinstance(status_code, IntEnum): - status_code = int(status_code) - route.status_code = status_code - if route.response_model: - assert is_body_allowed_for_status_code(status_code), ( - f"Status code {status_code} must not have a response body" - ) - response_name = "Response_" + route.unique_id - route.response_field = create_model_field( - name=response_name, - type_=route.response_model, - mode="serialization", - ) - else: - route.response_field = None - if route.stream_item_type: - stream_item_name = "StreamItem_" + route.unique_id - route.stream_item_field = create_model_field( - name=stream_item_name, - type_=route.stream_item_type, - mode="serialization", - ) - else: - route.stream_item_field = None - route.dependencies = list(dependencies or []) - route.description = description or inspect.cleandoc(route.endpoint.__doc__ or "") - # if a "form feed" character (page break) is found in the description text, - # truncate description text to the content preceding the first "form feed" - route.description = route.description.split("\f")[0].strip() - response_fields = {} - for additional_status_code, response in route.responses.items(): - assert isinstance(response, dict), "An additional response must be a dict" - model = response.get("model") - if model: - assert is_body_allowed_for_status_code(additional_status_code), ( - f"Status code {additional_status_code} must not have a response body" - ) - response_name = f"Response_{additional_status_code}_{route.unique_id}" - response_field = create_model_field( - name=response_name, type_=model, mode="serialization" - ) - response_fields[additional_status_code] = response_field - if response_fields: - route.response_fields = response_fields - else: - route.response_fields = {} - - assert callable(endpoint), "An endpoint must be a callable" - route.dependant = get_dependant( - path=route.path_format, call=route.endpoint, scope="function" - ) - for depends in route.dependencies[::-1]: - route.dependant.dependencies.insert( - 0, - get_parameterless_sub_dependant(depends=depends, path=route.path_format), - ) - route._flat_dependant = get_flat_dependant(route.dependant) - route._embed_body_fields = _should_embed_body_fields( - route._flat_dependant.body_params - ) - route.body_field = get_body_field( - flat_dependant=route._flat_dependant, - name=route.unique_id, - embed_body_fields=route._embed_body_fields, - ) - # Detect generator endpoints that should stream as JSONL or SSE - is_generator = ( - route.dependant.is_async_gen_callable or route.dependant.is_gen_callable - ) - route.is_sse_stream = is_generator and lenient_issubclass( - response_class, EventSourceResponse - ) - route.is_json_stream = is_generator and isinstance( - response_class, DefaultPlaceholder - ) - - -class APIRoute(routing.Route): - stream_item_type: Any | None - response_model: Any - summary: str | None - response_description: str - deprecated: bool | None - operation_id: str | None - response_model_include: IncEx | None - response_model_exclude: IncEx | None - response_model_by_alias: bool - response_model_exclude_unset: bool - response_model_exclude_defaults: bool - response_model_exclude_none: bool - include_in_schema: bool - response_class: type[Response] | DefaultPlaceholder - dependency_overrides_provider: Any | None - callbacks: list[BaseRoute] | None - openapi_extra: dict[str, Any] | None - generate_unique_id_function: Callable[[Any], str] | DefaultPlaceholder - strict_content_type: bool | DefaultPlaceholder - tags: list[str | Enum] - responses: dict[int | str, dict[str, Any]] - unique_id: str - status_code: int | None - response_field: ModelField | None - stream_item_field: ModelField | None - dependencies: list[params.Depends] - description: str - response_fields: dict[int | str, ModelField] - dependant: Dependant - _flat_dependant: Dependant - _embed_body_fields: bool - body_field: ModelField | None - is_sse_stream: bool - is_json_stream: bool - - def __init__( - self, - path: str, - endpoint: Callable[..., Any], - *, - response_model: Any = Default(None), - status_code: int | None = None, - tags: list[str | Enum] | None = None, - dependencies: Sequence[params.Depends] | None = None, - summary: str | None = None, - description: str | None = None, - response_description: str = "Successful Response", - responses: dict[int | str, dict[str, Any]] | None = None, - deprecated: bool | None = None, - name: str | None = None, - methods: set[str] | list[str] | None = None, - operation_id: str | None = None, - response_model_include: IncEx | None = None, - response_model_exclude: IncEx | None = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: type[Response] | DefaultPlaceholder = Default(JSONResponse), - dependency_overrides_provider: Any | None = None, - callbacks: list[BaseRoute] | None = None, - openapi_extra: dict[str, Any] | None = None, - generate_unique_id_function: Callable[["APIRoute"], str] - | DefaultPlaceholder = Default(generate_unique_id), - strict_content_type: bool | DefaultPlaceholder = Default(True), - ) -> None: - _populate_api_route_state( - cast(_APIRouteLike, self), - path, - endpoint, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - name=name, - methods=methods, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - dependency_overrides_provider=dependency_overrides_provider, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - strict_content_type=strict_content_type, - ) - self.app = request_response(self.get_route_handler()) - - def get_route_handler(self) -> Callable[[Request], Coroutine[Any, Any, Response]]: - route = cast(_APIRouteLike, self) - # TODO: Replace or deprecate this no-scope hook so included-route - # effective context can be passed explicitly instead of via ContextVar. - effective_context = _effective_route_context_var.get() - if effective_context is not None and effective_context.original_route is self: - route = cast(_APIRouteLike, effective_context) - return get_request_handler( - dependant=route.dependant, - body_field=route.body_field, - status_code=route.status_code, - response_class=route.response_class, - response_field=route.response_field, - response_model_include=route.response_model_include, - response_model_exclude=route.response_model_exclude, - response_model_by_alias=route.response_model_by_alias, - response_model_exclude_unset=route.response_model_exclude_unset, - response_model_exclude_defaults=route.response_model_exclude_defaults, - response_model_exclude_none=route.response_model_exclude_none, - dependency_overrides_provider=route.dependency_overrides_provider, - embed_body_fields=route._embed_body_fields, - strict_content_type=route.strict_content_type, - stream_item_field=route.stream_item_field, - is_json_stream=route.is_json_stream, - ) - - def matches(self, scope: Scope) -> tuple[Match, Scope]: - effective_context = _get_scope_effective_route_context(scope) - if effective_context is not None and effective_context.original_route is self: - match, child_scope = effective_context.matches(scope) - else: - match, child_scope = super().matches(scope) - if match != Match.NONE: - child_scope["route"] = self - return match, child_scope - - async def handle(self, scope: Scope, receive: Receive, send: Send) -> None: - effective_context = _get_scope_effective_route_context(scope) - if effective_context is not None and effective_context.original_route is self: - methods = effective_context.methods - if methods and scope["method"] not in methods: - headers = {"Allow": ", ".join(methods)} - if "app" in scope: - raise HTTPException(status_code=405, headers=headers) - response = PlainTextResponse( - "Method Not Allowed", status_code=405, headers=headers - ) - await response(scope, receive, send) - return - token = _effective_route_context_var.set(effective_context) - try: - app = request_response(self.get_route_handler()) - finally: - _effective_route_context_var.reset(token) - await app(scope, receive, send) - return - await super().handle(scope, receive, send) - - -@dataclass -class _RouterIncludeContext: - included_router: "APIRouter" - prefix: str = "" - tags: list[str | Enum] = field(default_factory=list) - dependencies: list[params.Depends] = field(default_factory=list) - default_response_class: type[Response] | DefaultPlaceholder = field( - default_factory=lambda: Default(JSONResponse) - ) - responses: dict[int | str, dict[str, Any]] = field(default_factory=dict) - callbacks: list[BaseRoute] = field(default_factory=list) - deprecated: bool | None = None - include_in_schema: bool = True - generate_unique_id_function: Callable[[APIRoute], str] | DefaultPlaceholder = field( - default_factory=lambda: Default(generate_unique_id) - ) - strict_content_type: bool | DefaultPlaceholder = field( - default_factory=lambda: Default(True) - ) - dependency_overrides_provider: Any | None = None - - @classmethod - def for_include( - cls, - *, - parent_router: "APIRouter", - included_router: "APIRouter", - prefix: str = "", - tags: list[str | Enum] | None = None, - dependencies: Sequence[params.Depends] | None = None, - default_response_class: type[Response] | DefaultPlaceholder = Default( - JSONResponse - ), - responses: dict[int | str, dict[str, Any]] | None = None, - callbacks: list[BaseRoute] | None = None, - deprecated: bool | None = None, - include_in_schema: bool = True, - generate_unique_id_function: Callable[[APIRoute], str] - | DefaultPlaceholder = Default(generate_unique_id), - ) -> "_RouterIncludeContext": - return cls( - included_router=included_router, - prefix=parent_router.prefix + prefix, - tags=[*parent_router.tags, *(tags or [])], - dependencies=[*parent_router.dependencies, *(dependencies or [])], - default_response_class=get_value_or_default( - default_response_class, parent_router.default_response_class - ), - responses={**parent_router.responses, **(responses or {})}, - callbacks=[*parent_router.callbacks, *(callbacks or [])], - deprecated=deprecated or parent_router.deprecated, - include_in_schema=parent_router.include_in_schema and include_in_schema, - generate_unique_id_function=get_value_or_default( - generate_unique_id_function, parent_router.generate_unique_id_function - ), - strict_content_type=parent_router.strict_content_type, - dependency_overrides_provider=parent_router.dependency_overrides_provider, - ) - - def combine( - self, child_context: "_RouterIncludeContext" - ) -> "_RouterIncludeContext": - return _RouterIncludeContext( - included_router=child_context.included_router, - prefix=self.prefix + child_context.prefix, - tags=[*self.tags, *child_context.tags], - dependencies=[*self.dependencies, *child_context.dependencies], - default_response_class=get_value_or_default( - child_context.default_response_class, self.default_response_class - ), - responses={**self.responses, **child_context.responses}, - callbacks=[*self.callbacks, *child_context.callbacks], - deprecated=self.deprecated or child_context.deprecated, - include_in_schema=self.include_in_schema - and child_context.include_in_schema, - generate_unique_id_function=get_value_or_default( - child_context.generate_unique_id_function, - self.generate_unique_id_function, - ), - strict_content_type=get_value_or_default( - child_context.strict_content_type, self.strict_content_type - ), - dependency_overrides_provider=self.dependency_overrides_provider, - ) - - def path_for(self, route: _RouteWithPath) -> str: - return self.prefix + route.path - - -@dataclass -class _EffectiveRouteContext: - original_route: BaseRoute - starlette_route: BaseRoute | None = None - path: str = "" - endpoint: Callable[..., Any] | None = None - stream_item_type: Any | None = None - response_model: Any = None - summary: str | None = None - response_description: str = "Successful Response" - deprecated: bool | None = None - operation_id: str | None = None - response_model_include: IncEx | None = None - response_model_exclude: IncEx | None = None - response_model_by_alias: bool = True - response_model_exclude_unset: bool = False - response_model_exclude_defaults: bool = False - response_model_exclude_none: bool = False - include_in_schema: bool = True - response_class: type[Response] | DefaultPlaceholder = field( - default_factory=lambda: Default(JSONResponse) - ) - dependency_overrides_provider: Any | None = None - callbacks: list[BaseRoute] | None = None - openapi_extra: dict[str, Any] | None = None - generate_unique_id_function: Callable[[Any], str] | DefaultPlaceholder = field( - default_factory=lambda: Default(generate_unique_id) - ) - strict_content_type: bool | DefaultPlaceholder = field( - default_factory=lambda: Default(True) - ) - tags: list[str | Enum] = field(default_factory=list) - responses: dict[int | str, dict[str, Any]] = field(default_factory=dict) - name: str = "" - path_regex: Any = None - path_format: str = "" - param_convertors: dict[str, Any] = field(default_factory=dict) - methods: set[str] = field(default_factory=set) - unique_id: str = "" - status_code: int | None = None - response_field: ModelField | None = None - stream_item_field: ModelField | None = None - dependencies: list[params.Depends] = field(default_factory=list) - description: str = "" - response_fields: dict[int | str, ModelField] = field(default_factory=dict) - dependant: Dependant | None = None - _flat_dependant: Dependant | None = None - _embed_body_fields: bool = False - body_field: ModelField | None = None - is_sse_stream: bool = False - is_json_stream: bool = False - - @classmethod - def from_api_route( - cls, - *, - original_route: APIRoute, - include_context: _RouterIncludeContext, - ) -> "_EffectiveRouteContext": - route = cast(_APIRouteLike, original_route) - context = cls(original_route=original_route) - _populate_api_route_state( - cast(_APIRouteLike, context), - include_context.path_for(original_route), - route.endpoint, - response_model=route.response_model, - status_code=route.status_code, - tags=[*include_context.tags, *route.tags], - dependencies=[*include_context.dependencies, *route.dependencies], - summary=route.summary, - description=route.description, - response_description=route.response_description, - responses={**include_context.responses, **route.responses}, - deprecated=route.deprecated or include_context.deprecated, - methods=route.methods, - operation_id=route.operation_id, - response_model_include=route.response_model_include, - response_model_exclude=route.response_model_exclude, - response_model_by_alias=route.response_model_by_alias, - response_model_exclude_unset=route.response_model_exclude_unset, - response_model_exclude_defaults=route.response_model_exclude_defaults, - response_model_exclude_none=route.response_model_exclude_none, - include_in_schema=route.include_in_schema - and include_context.include_in_schema, - response_class=get_value_or_default( - route.response_class, - include_context.included_router.default_response_class, - include_context.default_response_class, - ), - name=route.name, - dependency_overrides_provider=include_context.dependency_overrides_provider, - callbacks=[*include_context.callbacks, *(route.callbacks or [])], - openapi_extra=route.openapi_extra, - generate_unique_id_function=get_value_or_default( - route.generate_unique_id_function, - include_context.included_router.generate_unique_id_function, - include_context.generate_unique_id_function, - ), - strict_content_type=get_value_or_default( - route.strict_content_type, - include_context.included_router.strict_content_type, - include_context.strict_content_type, - ), - ) - return context - - def matches(self, scope: Scope) -> tuple[Match, Scope]: - if not isinstance(self.original_route, APIRoute): - assert self.starlette_route is not None - return self.starlette_route.matches(scope) - if scope["type"] != "http": - return Match.NONE, {} - route_path = get_route_path(scope) - match = self.path_regex.match(route_path) - if not match: - return Match.NONE, {} - matched_params = match.groupdict() - for key, value in matched_params.items(): - matched_params[key] = self.param_convertors[key].convert(value) - path_params = dict(scope.get("path_params", {})) - path_params.update(matched_params) - child_scope = {"endpoint": self.endpoint, "path_params": path_params} - methods = self.methods - if methods and scope["method"] not in methods: - return Match.PARTIAL, child_scope - return Match.FULL, child_scope - - def url_path_for(self, name: str, /, **path_params: Any) -> Any: - if not isinstance(self.original_route, APIRoute): - assert self.starlette_route is not None - return self.starlette_route.url_path_for(name, **path_params) - seen_params = set(path_params.keys()) - param_convertors = self.param_convertors - expected_params = set(param_convertors.keys()) - if name != self.name or seen_params != expected_params: - raise routing.NoMatchFound(name, path_params) - path, remaining_params = routing.replace_params( - self.path_format, param_convertors, path_params - ) - assert not remaining_params - return URLPath(path=path, protocol="http") - - -@dataclass(frozen=True) -class RouteContext: - route: BaseRoute - _route_context: _EffectiveRouteContext | None = field(default=None, repr=False) - - @property - def original_route(self) -> BaseRoute: - if self._route_context is not None: - return self._route_context.original_route - return self.route - - @property - def _effective_route(self) -> BaseRoute | _EffectiveRouteContext: - if self._route_context is not None: - return self._route_context - return self.route - - @property - def path(self) -> str | None: - return getattr(self._effective_route, "path", None) - - @property - def path_format(self) -> str | None: - return getattr(self._effective_route, "path_format", None) - - @property - def name(self) -> str | None: - return getattr(self._effective_route, "name", None) - - @property - def methods(self) -> set[str] | None: - return getattr(self._effective_route, "methods", None) - - @property - def endpoint(self) -> Callable[..., Any] | None: - return getattr(self._effective_route, "endpoint", None) - - def __getattr__(self, name: str) -> Any: - return getattr(self._effective_route, name) - - -@dataclass -class _IncludedRouter(BaseRoute): - original_router: "APIRouter" - include_context: _RouterIncludeContext - _effective_candidates: list["_EffectiveRouteContext | _IncludedRouter"] = field( - default_factory=list - ) - _effective_candidates_version: int | None = None - _effective_low_priority_routes: list["_EffectiveRouteContext"] = field( - default_factory=list - ) - _effective_low_priority_routes_version: int | None = None - - def effective_candidates(self) -> list["_EffectiveRouteContext | _IncludedRouter"]: - routes_version = self.original_router._get_routes_version() - if routes_version == self._effective_candidates_version: - return self._effective_candidates - self._effective_candidates = [] - candidates = self.original_router.routes - for route in candidates: - if isinstance(route, _IncludedRouter): - child_context = self.include_context.combine(route.include_context) - child_branch = _IncludedRouter( - original_router=route.original_router, - include_context=child_context, - ) - self._effective_candidates.append(child_branch) - continue - route_context = self._build_effective_context(route) - if route_context is not None: - self._effective_candidates.append(route_context) - self._effective_candidates_version = routes_version - return self._effective_candidates - - def effective_low_priority_routes(self) -> list["_EffectiveRouteContext"]: - routes_version = self.original_router._get_routes_version() - if routes_version == self._effective_low_priority_routes_version: - return self._effective_low_priority_routes - self._effective_low_priority_routes = [] - for route in self.original_router._low_priority_routes: - route_context = self._build_effective_context(route) - if route_context is not None: - self._effective_low_priority_routes.append(route_context) - for route in self.original_router.routes: - if isinstance(route, _IncludedRouter): - child_context = self.include_context.combine(route.include_context) - child_branch = _IncludedRouter( - original_router=route.original_router, - include_context=child_context, - ) - self._effective_low_priority_routes.extend( - child_branch.effective_low_priority_routes() - ) - self._effective_low_priority_routes_version = routes_version - return self._effective_low_priority_routes - - def _build_effective_context( - self, route: BaseRoute - ) -> _EffectiveRouteContext | None: - if isinstance(route, APIRoute): - return _EffectiveRouteContext.from_api_route( - original_route=route, - include_context=self.include_context, - ) - if isinstance(route, _FrontendRouteGroup): - return _EffectiveRouteContext( - original_route=route, - starlette_route=route.with_prefix(self.include_context.prefix), - ) - if isinstance(route, routing.Route): - starlette_route: BaseRoute = routing.Route( - self.include_context.path_for(route), - endpoint=route.endpoint, - methods=list(route.methods or []), - name=route.name, - include_in_schema=route.include_in_schema, - ) - return _EffectiveRouteContext( - original_route=route, - starlette_route=starlette_route, - ) - if isinstance(route, APIWebSocketRoute): - starlette_route = APIWebSocketRoute( - self.include_context.path_for(route), - endpoint=route.endpoint, - name=route.name, - dependencies=[*self.include_context.dependencies, *route.dependencies], - dependency_overrides_provider=( - self.include_context.dependency_overrides_provider - ), - ) - return _EffectiveRouteContext( - original_route=route, - starlette_route=starlette_route, - ) - if isinstance(route, routing.WebSocketRoute): - starlette_route = routing.WebSocketRoute( - self.include_context.path_for(route), route.endpoint, name=route.name - ) - return _EffectiveRouteContext( - original_route=route, - starlette_route=starlette_route, - ) - if isinstance(route, routing.Mount): - starlette_route = copy.copy(route) - starlette_route.path = self.include_context.path_for(route).rstrip("/") - ( - starlette_route.path_regex, - starlette_route.path_format, - starlette_route.param_convertors, - ) = compile_path(starlette_route.path + "/{path:path}") - return _EffectiveRouteContext( - original_route=route, - starlette_route=starlette_route, - ) - if isinstance(route, routing.Host): - if self.include_context.prefix: - prefixed_app: ASGIApp = routing.Router( - routes=[routing.Mount(self.include_context.prefix, app=route.app)] - ) - else: - prefixed_app = route.app - starlette_route = routing.Host( - route.host, app=prefixed_app, name=route.name - ) - return _EffectiveRouteContext( - original_route=route, - starlette_route=starlette_route, - ) - return None - - def _match( - self, scope: Scope - ) -> tuple[Match, Scope, BaseRoute | None, _EffectiveRouteContext | None]: - partial: tuple[Scope, BaseRoute, _EffectiveRouteContext | None] | None = None - for candidate in self.effective_candidates(): - if isinstance(candidate, _IncludedRouter): - match, child_scope = candidate.matches(scope) - route: BaseRoute = candidate - route_context = None - elif isinstance(candidate.original_route, APIRoute): - route_context = candidate - fastapi_scope = _get_fastapi_scope(scope) - previous_context = fastapi_scope.get( - _FASTAPI_EFFECTIVE_ROUTE_CONTEXT_KEY, _SCOPE_MISSING - ) - fastapi_scope[_FASTAPI_EFFECTIVE_ROUTE_CONTEXT_KEY] = route_context - try: - match, child_scope = candidate.original_route.matches(scope) - finally: - _restore_fastapi_scope_key( - scope, _FASTAPI_EFFECTIVE_ROUTE_CONTEXT_KEY, previous_context - ) - route = candidate.original_route - else: - route_context = candidate - match, child_scope = candidate.matches(scope) - route = candidate.starlette_route or candidate.original_route - if match == Match.FULL: - return match, child_scope, route, route_context - if match == Match.PARTIAL and partial is None: - partial = (child_scope, route, route_context) - if partial is not None: - child_scope, route, route_context = partial - return Match.PARTIAL, child_scope, route, route_context - return Match.NONE, {}, None, None - - def matches(self, scope: Scope) -> tuple[Match, Scope]: - fastapi_scope = _get_fastapi_scope(scope) - previous_router = fastapi_scope.get( - _FASTAPI_INCLUDED_ROUTER_KEY, _SCOPE_MISSING - ) - fastapi_scope[_FASTAPI_INCLUDED_ROUTER_KEY] = self - try: - match, _ = self.original_router.matches(scope) - return match, {} - finally: - _restore_fastapi_scope_key( - scope, _FASTAPI_INCLUDED_ROUTER_KEY, previous_router - ) - - async def handle(self, scope: Scope, receive: Receive, send: Send) -> None: - _get_fastapi_scope(scope)[_FASTAPI_INCLUDED_ROUTER_KEY] = self - await self.original_router.handle(scope, receive, send) - - async def _handle_selected( - self, scope: Scope, receive: Receive, send: Send - ) -> None: - match, child_scope, route, effective_context = self._match(scope) - if match == Match.NONE or route is None: - await self.original_router.default(scope, receive, send) - return - scope.update(child_scope) - if isinstance(route, _IncludedRouter): - await route.handle(scope, receive, send) - return - if effective_context is not None: - _get_fastapi_scope(scope)[_FASTAPI_EFFECTIVE_ROUTE_CONTEXT_KEY] = ( - effective_context - ) - original_route = effective_context.original_route - if isinstance(original_route, APIRoute): - scope["route"] = original_route - await original_route.handle(scope, receive, send) - return - await route.handle(scope, receive, send) - - def effective_route_contexts(self) -> Iterator[_EffectiveRouteContext]: - for candidate in self.effective_candidates(): - if isinstance(candidate, _IncludedRouter): - yield from candidate.effective_route_contexts() - else: - yield candidate - - def url_path_for(self, name: str, /, **path_params: Any) -> Any: - for route_context in self.effective_route_contexts(): - try: - return route_context.url_path_for(name, **path_params) - except routing.NoMatchFound: - pass - raise routing.NoMatchFound(name, path_params) - - -def _iter_included_route_candidates(routes: Sequence[BaseRoute]) -> Iterator[BaseRoute]: - for route, route_context in _iter_routes_with_context(routes): - if route_context is not None and route_context.starlette_route is not None: - yield route_context.starlette_route - else: - yield route - - -def iter_route_contexts( - routes: Sequence[BaseRoute | RouteContext], -) -> Iterator[RouteContext]: - for route in routes: - if isinstance(route, RouteContext): - yield route - continue - for original_route, route_context in _iter_routes_with_context([route]): - if route_context is None: - yield RouteContext(original_route) - else: - yield RouteContext(original_route, route_context) - - -def _iter_routes_with_context( - routes: Sequence[BaseRoute], -) -> Iterator[tuple[BaseRoute, _EffectiveRouteContext | None]]: - for route in routes: - if isinstance(route, _IncludedRouter): - for route_context in route.effective_route_contexts(): - yield route_context.original_route, route_context - else: - yield route, None - - -def _normalize_frontend_path(path: str) -> str: - if not path: - raise AssertionError("A frontend path cannot be empty") - if not path.startswith("/"): - raise AssertionError("A frontend path must start with '/'") - if path != "/": - path = path.rstrip("/") - return path - - -def _join_frontend_paths(prefix: str, path: str) -> str: - if not prefix: - return path - if path == "/": - return prefix - return prefix + path - - -def _frontend_path_specificity(path: str) -> int: - if path == "/": - return 0 - return len(path) - - -def _get_resolved_absolute_path(path: str | os.PathLike[str]) -> str: - return os.path.realpath(os.fspath(path)) - - -class _FrontendStaticFiles(StaticFiles): - def __init__( - self, - *, - directory: str | os.PathLike[str], - fallback: Literal["auto", "index.html", "404.html"] | None, - check_dir: bool = True, - ) -> None: - self.fallback = fallback - if check_dir and not os.path.isdir(directory): - raise RuntimeError( - f"Frontend directory '{directory}' does not exist. " - f"Resolved absolute path: '{_get_resolved_absolute_path(directory)}'" - ) - super().__init__( - directory=directory, - html=True, - check_dir=check_dir, - follow_symlink=False, - ) - if check_dir and fallback in {"index.html", "404.html"}: - self._check_fallback_file(fallback) - - def _check_fallback_file(self, fallback: str) -> None: - _, stat_result = self.lookup_path(fallback) - if stat_result is None or not stat.S_ISREG(stat_result.st_mode): - raise RuntimeError( - f"Frontend fallback file '{fallback}' does not exist in " - f"directory '{self.directory}'. Resolved absolute directory: " - f"'{self._get_resolved_directory()}'" - ) - - def _get_resolved_directory(self) -> str: - assert self.directory is not None - return _get_resolved_absolute_path(self.directory) - - def get_path(self, scope: Scope) -> str: - path = _get_fastapi_scope(scope).get(_FASTAPI_FRONTEND_PATH_KEY, "") - assert isinstance(path, str) - return os.path.normpath(os.path.join(*path.split("/"))) - - async def get_response(self, path: str, scope: Scope) -> Response: - if scope["method"] not in ("GET", "HEAD"): - raise HTTPException(status_code=405) - - try: - full_path, stat_result = await run_in_threadpool(self.lookup_path, path) - except PermissionError: - raise HTTPException(status_code=401) from None - except OSError as exc: - if exc.errno == errno.ENAMETOOLONG: - raise HTTPException(status_code=404) from None - raise exc - except ValueError: - raise HTTPException(status_code=404) from None - - if stat_result and stat.S_ISREG(stat_result.st_mode): - return self.file_response(full_path, stat_result, scope) - - if stat_result and stat.S_ISDIR(stat_result.st_mode): - index_path = os.path.join(path, "index.html") - full_path, stat_result = await run_in_threadpool( - self.lookup_path, index_path - ) - if stat_result is not None and stat.S_ISREG(stat_result.st_mode): - if not scope["path"].endswith("/"): - url = URL(scope=scope) - url = url.replace(path=url.path + "/") - return RedirectResponse(url=url) - return self.file_response(full_path, stat_result, scope) - - if self.fallback == "404.html" or ( - self.fallback == "auto" and self._fallback_file_exists("404.html") - ): - return await self._fallback_response("404.html", scope, status_code=404) - - if ( - self.fallback == "index.html" - or (self.fallback == "auto" and self._fallback_file_exists("index.html")) - ) and _is_frontend_navigation_request(scope): - return await self._fallback_response("index.html", scope, status_code=200) - - raise HTTPException(status_code=404) - - def _fallback_file_exists(self, fallback: str) -> bool: - _, stat_result = self.lookup_path(fallback) - return stat_result is not None and stat.S_ISREG(stat_result.st_mode) - - async def _fallback_response( - self, fallback: str, scope: Scope, *, status_code: int - ) -> Response: - full_path, stat_result = await run_in_threadpool(self.lookup_path, fallback) - if stat_result is None or not stat.S_ISREG(stat_result.st_mode): - raise RuntimeError( - f"Frontend fallback file '{fallback}' does not exist in " - f"directory '{self.directory}'. Resolved absolute directory: " - f"'{self._get_resolved_directory()}'" - ) - return self.file_response( - full_path, stat_result, scope, status_code=status_code - ) - - -def _iter_accept_media_types(accept: str) -> Iterator[tuple[str, float]]: - for raw_value in accept.split(","): - message = email.message.Message() - message["content-type"] = raw_value.strip() - q = message.get_param("q") - quality = 1.0 - if isinstance(q, str): - try: - quality = float(q) - except ValueError: - pass - yield ( - f"{message.get_content_maintype()}/{message.get_content_subtype()}", - quality, - ) - - -def _is_frontend_navigation_request(scope: Scope) -> bool: - route_path = get_route_path(scope) - final_segment = route_path.rsplit("/", 1)[-1] - if os.path.splitext(final_segment)[1]: - return False - request = Request(scope) - wildcard_accepted = False - html_rejected = False - for media_type, quality in _iter_accept_media_types( - request.headers.get("accept", "") - ): - if media_type in {"text/html", "application/xhtml+xml"}: - if quality == 0: - html_rejected = True - else: - return True - elif media_type == "*/*" and quality != 0: - wildcard_accepted = True - return wildcard_accepted and not html_rejected - - -class _FrontendRoute(BaseRoute): - def __init__( - self, - path: str, - *, - directory: str | os.PathLike[str], - fallback: Literal["auto", "index.html", "404.html"] | None = "auto", - check_dir: bool = True, - ) -> None: - if fallback not in {"auto", "index.html", "404.html", None}: - raise AssertionError( - "fallback must be 'auto', 'index.html', '404.html', or None" - ) - self.path = _normalize_frontend_path(path) - self.methods = {"GET", "HEAD"} - self.app = _FrontendStaticFiles( - directory=directory, fallback=fallback, check_dir=check_dir - ) - - def with_path(self, path: str) -> "_FrontendRoute": - route = copy.copy(self) - route.path = _normalize_frontend_path(path) - return route - - def matches(self, scope: Scope) -> tuple[Match, Scope]: - if scope["type"] != "http": - return Match.NONE, {} - frontend_path = self._get_frontend_path(get_route_path(scope)) - if frontend_path is None: - return Match.NONE, {} - child_scope = {_FASTAPI_SCOPE_KEY: {_FASTAPI_FRONTEND_PATH_KEY: frontend_path}} - if scope["method"] not in self.methods: - return Match.PARTIAL, child_scope - return Match.FULL, child_scope - - def _get_frontend_path(self, route_path: str) -> str | None: - if self.path == "/": - return route_path.lstrip("/") - if route_path == self.path: - return "" - prefix = self.path + "/" - if route_path.startswith(prefix): - return route_path[len(prefix) :] - return None - - async def handle(self, scope: Scope, receive: Receive, send: Send) -> None: - await self.app(scope, receive, send) - - def url_path_for(self, name: str, /, **path_params: Any) -> URLPath: - raise NoMatchFound(name, path_params) - - -class _FrontendRouteGroup(BaseRoute): - def __init__(self) -> None: - self.routes: list[_FrontendRoute] = [] - - def add_frontend_route( - self, - path: str, - *, - directory: str | os.PathLike[str], - fallback: Literal["auto", "index.html", "404.html"] | None = "auto", - check_dir: bool = True, - ) -> None: - self.routes.append( - _FrontendRoute( - path, - directory=directory, - fallback=fallback, - check_dir=check_dir, - ) - ) - - def with_prefix(self, prefix: str) -> "_FrontendRouteGroup": - route_group = copy.copy(self) - route_group.routes = [ - route.with_path(_join_frontend_paths(prefix, route.path)) - for route in self.routes - ] - return route_group - - def matches(self, scope: Scope) -> tuple[Match, Scope]: - match, child_scope, _ = self._match(scope) - return match, child_scope - - def _match(self, scope: Scope) -> tuple[Match, Scope, _FrontendRoute | None]: - full: tuple[Scope, _FrontendRoute] | None = None - partial: tuple[Scope, _FrontendRoute] | None = None - for route in self.routes: - match, child_scope = route.matches(scope) - if match == Match.FULL: - if full is None or _frontend_path_specificity( - route.path - ) > _frontend_path_specificity(full[1].path): - full = (child_scope, route) - elif match == Match.PARTIAL: - if partial is None or _frontend_path_specificity( - route.path - ) > _frontend_path_specificity(partial[1].path): - partial = (child_scope, route) - if full is not None: - child_scope, route = full - return Match.FULL, child_scope, route - if partial is not None: - child_scope, route = partial - return Match.PARTIAL, child_scope, route - return Match.NONE, {}, None - - async def handle(self, scope: Scope, receive: Receive, send: Send) -> None: - match, child_scope, route = self._match(scope) - if match == Match.NONE or route is None: - raise HTTPException(status_code=404) - _update_scope(scope, child_scope) - await route.handle(scope, receive, send) - - def url_path_for(self, name: str, /, **path_params: Any) -> URLPath: - raise NoMatchFound(name, path_params) - - -class APIRouter(routing.Router): - """ - `APIRouter` class, used to group *path operations*, for example to structure - an app in multiple files. It would then be included in the `FastAPI` app, or - in another `APIRouter` (ultimately included in the app). - - Read more about it in the - [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/). - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - - app = FastAPI() - router = APIRouter() - - - @router.get("/users/", tags=["users"]) - async def read_users(): - return [{"username": "Rick"}, {"username": "Morty"}] - - - app.include_router(router) - ``` - """ - - def __init__( - self, - *, - prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "", - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to all the *path operations* in this - router. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[params.Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to all the - *path operations* in this router. - - Read more about it in the - [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). - """ - ), - ] = None, - default_response_class: Annotated[ - type[Response], - Doc( - """ - The default response class to be used. - - Read more in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class). - """ - ), - ] = Default(JSONResponse), - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses to be shown in OpenAPI. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/). - - And in the - [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - OpenAPI callbacks that should apply to all *path operations* in this - router. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - routes: Annotated[ - list[BaseRoute] | None, - Doc( - """ - **Note**: you probably shouldn't use this parameter, it is inherited - from Starlette and supported for compatibility. - - --- - - A list of routes to serve incoming HTTP and WebSocket requests. - """ - ), - deprecated( - """ - You normally wouldn't use this parameter with FastAPI, it is inherited - from Starlette and supported for compatibility. - - In FastAPI, you normally would use the *path operation methods*, - like `router.get()`, `router.post()`, etc. - """ - ), - ] = None, - redirect_slashes: Annotated[ - bool, - Doc( - """ - Whether to detect and redirect slashes in URLs when the client doesn't - use the same format. - """ - ), - ] = True, - default: Annotated[ - ASGIApp | None, - Doc( - """ - Default function handler for this router. Used to handle - 404 Not Found errors. - """ - ), - ] = None, - dependency_overrides_provider: Annotated[ - Any | None, - Doc( - """ - Only used internally by FastAPI to handle dependency overrides. - - You shouldn't need to use it. It normally points to the `FastAPI` app - object. - """ - ), - ] = None, - route_class: Annotated[ - type[APIRoute], - Doc( - """ - Custom route (*path operation*) class to be used by this router. - - Read more about it in the - [FastAPI docs for Custom Request and APIRoute class](https://fastapi.tiangolo.com/how-to/custom-request-and-route/#custom-apiroute-class-in-a-router). - """ - ), - ] = APIRoute, - on_startup: Annotated[ - Sequence[Callable[[], Any]] | None, - Doc( - """ - A list of startup event handler functions. - - You should instead use the `lifespan` handlers. - - Read more in the [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/). - """ - ), - ] = None, - on_shutdown: Annotated[ - Sequence[Callable[[], Any]] | None, - Doc( - """ - A list of shutdown event handler functions. - - You should instead use the `lifespan` handlers. - - Read more in the - [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/). - """ - ), - ] = None, - # the generic to Lifespan[AppType] is the type of the top level application - # which the router cannot know statically, so we use typing.Any - lifespan: Annotated[ - Lifespan[Any] | None, - Doc( - """ - A `Lifespan` context manager handler. This replaces `startup` and - `shutdown` functions with a single context manager. - - Read more in the - [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark all *path operations* in this router as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - To include (or not) all the *path operations* in this router in the - generated OpenAPI. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - strict_content_type: Annotated[ - bool, - Doc( - """ - Enable strict checking for request Content-Type headers. - - When `True` (the default), requests with a body that do not include - a `Content-Type` header will **not** be parsed as JSON. - - This prevents potential cross-site request forgery (CSRF) attacks - that exploit the browser's ability to send requests without a - Content-Type header, bypassing CORS preflight checks. In particular - applicable for apps that need to be run locally (in localhost). - - When `False`, requests without a `Content-Type` header will have - their body parsed as JSON, which maintains compatibility with - certain clients that don't send `Content-Type` headers. - - Read more about it in the - [FastAPI docs for Strict Content-Type](https://fastapi.tiangolo.com/advanced/strict-content-type/). - """ - ), - ] = Default(True), - ) -> None: - # Determine the lifespan context to use - if lifespan is None: - # Use the default lifespan that runs on_startup/on_shutdown handlers - lifespan_context: Lifespan[Any] = _DefaultLifespan(self) - elif inspect.isasyncgenfunction(lifespan): - lifespan_context = asynccontextmanager(lifespan) - elif inspect.isgeneratorfunction(lifespan): - lifespan_context = _wrap_gen_lifespan_context(lifespan) - else: - lifespan_context = lifespan - self.lifespan_context = lifespan_context - - super().__init__( - routes=routes, - redirect_slashes=redirect_slashes, - default=default, - lifespan=lifespan_context, - ) - if prefix: - assert prefix.startswith("/"), "A path prefix must start with '/'" - assert not prefix.endswith("/"), ( - "A path prefix must not end with '/', as the routes will start with '/'" - ) - - # Handle on_startup/on_shutdown locally since Starlette removed support - # Ref: https://github.com/Kludex/starlette/pull/3117 - # TODO: deprecate this once the lifespan (or alternative) interface is improved - self.on_startup: list[Callable[[], Any]] = ( - [] if on_startup is None else list(on_startup) - ) - self.on_shutdown: list[Callable[[], Any]] = ( - [] if on_shutdown is None else list(on_shutdown) - ) - - self.prefix = prefix - self.tags: list[str | Enum] = tags or [] - self.dependencies = list(dependencies or []) - self.deprecated = deprecated - self.include_in_schema = include_in_schema - self.responses = responses or {} - self.callbacks = callbacks or [] - self.dependency_overrides_provider = dependency_overrides_provider - self.route_class = route_class - self.default_response_class = default_response_class - self.generate_unique_id_function = generate_unique_id_function - self.strict_content_type = strict_content_type - self._routes_version = 0 - self._low_priority_routes: list[BaseRoute] = [] - self._frontend_routes: _FrontendRouteGroup | None = None - - def _mark_routes_changed(self) -> None: - self._routes_version += 1 - - def _get_routes_version(self, seen: set[int] | None = None) -> int: - if seen is None: - seen = set() - router_id = id(self) - if router_id in seen: - return self._routes_version - seen.add(router_id) - version = self._routes_version - for route in self.routes: - if isinstance(route, _IncludedRouter): - version += route.original_router._get_routes_version(seen) - return version - - def _contains_router( - self, router: "APIRouter", seen: set[int] | None = None - ) -> bool: - if seen is None: - seen = set() - router_id = id(self) - if router_id in seen: - return False - seen.add(router_id) - for route in self.routes: - if not isinstance(route, _IncludedRouter): - continue - if route.original_router is router: - return True - if route.original_router._contains_router(router, seen): - return True - return False - - def add_route( - self, - path: str, - endpoint: Callable[[Request], Awaitable[Response] | Response], - methods: Collection[str] | None = None, - name: str | None = None, - include_in_schema: bool = True, - ) -> None: - super().add_route( - path, - endpoint, - methods=methods, - name=name, - include_in_schema=include_in_schema, - ) - self._mark_routes_changed() - - def add_websocket_route( - self, - path: str, - endpoint: Callable[[WebSocket], Awaitable[None]], - name: str | None = None, - ) -> None: - super().add_websocket_route(path, endpoint, name=name) - self._mark_routes_changed() - - def frontend( - self, - path: Annotated[ - str, - Doc( - """ - The URL path prefix where the frontend build should be served. - """ - ), - ], - *, - directory: Annotated[ - str | os.PathLike[str], - Doc( - """ - The directory containing the static frontend build output. - """ - ), - ], - fallback: Annotated[ - Literal["auto", "index.html", "404.html"] | None, - Doc( - """ - The fallback file behavior for missing frontend paths. - """ - ), - ] = "auto", - check_dir: Annotated[ - bool, - Doc( - """ - Check that the frontend directory exists when the app is created. - """ - ), - ] = True, - ) -> None: - """ - Serve a static frontend build as low-priority routes. - - Use this for frontend tools that build static files into a directory, - such as `dist`. **FastAPI** path operations are checked first, and - the frontend files are checked only if no normal route matched. - - A typical project could look like this: - - ```text - . - ├── pyproject.toml - ├── app - │ ├── __init__.py - │ └── main.py - └── dist - ├── index.html - └── assets - └── app.js - ``` - - Then in `app/main.py`: - - ```python - from fastapi import APIRouter, FastAPI - - app = FastAPI() - router = APIRouter() - router.frontend("/", directory="dist") - app.include_router(router) - ``` - """ - normalized_path = _normalize_frontend_path(path) - if self._frontend_routes is None: - self._frontend_routes = _FrontendRouteGroup() - self._low_priority_routes.append(self._frontend_routes) - self._frontend_routes.add_frontend_route( - _join_frontend_paths(self.prefix, normalized_path), - directory=directory, - fallback=fallback, - check_dir=check_dir, - ) - self._mark_routes_changed() - - async def app(self, scope: Scope, receive: Receive, send: Send) -> None: - assert scope["type"] in ("http", "websocket", "lifespan") - - if "router" not in scope: - scope["router"] = self - - if scope["type"] == "lifespan": - await self.lifespan(scope, receive, send) - return - - partial: tuple[BaseRoute, Scope] | None = None - for route in self.routes: - match, child_scope = route.matches(scope) - if match == Match.FULL: - scope.update(child_scope) - await route.handle(scope, receive, send) - return - if match == Match.PARTIAL and partial is None: - partial = (route, child_scope) - - if partial is not None: - route, child_scope = partial - scope.update(child_scope) - await route.handle(scope, receive, send) - return - - route_path = get_route_path(scope) - if scope["type"] == "http" and self.redirect_slashes and route_path != "/": - redirect_scope = dict(scope) - if route_path.endswith("/"): - redirect_scope["path"] = redirect_scope["path"].rstrip("/") - else: - redirect_scope["path"] = redirect_scope["path"] + "/" - - for route in self.routes: - match, _ = route.matches(redirect_scope) - if match != Match.NONE: - redirect_url = URL(scope=redirect_scope) - response = RedirectResponse(url=str(redirect_url)) - await response(scope, receive, send) - return - - ( - low_priority_match, - low_priority_scope, - low_priority_route, - low_priority_context, - ) = self._match_low_priority(scope) - if low_priority_match != Match.NONE and low_priority_route is not None: - _update_scope(scope, low_priority_scope) - if low_priority_context is not None: - _get_fastapi_scope(scope)[_FASTAPI_EFFECTIVE_ROUTE_CONTEXT_KEY] = ( - low_priority_context - ) - original_route = low_priority_context.original_route - if isinstance(original_route, APIRoute): - scope["route"] = original_route - await original_route.handle(scope, receive, send) - return - await low_priority_route.handle(scope, receive, send) - return - - await self.default(scope, receive, send) - - async def handle(self, scope: Scope, receive: Receive, send: Send) -> None: - included_router = _get_scope_included_router(scope) - if ( - isinstance(included_router, _IncludedRouter) - and included_router.original_router is self - ): - await included_router._handle_selected(scope, receive, send) - return - await self.app(scope, receive, send) - - def matches(self, scope: Scope) -> tuple[Match, Scope]: - included_router = _get_scope_included_router(scope) - if ( - isinstance(included_router, _IncludedRouter) - and included_router.original_router is self - ): - match, child_scope, _, _ = included_router._match(scope) - return match, child_scope - return Match.NONE, {} - - def _iter_low_priority_routes( - self, - ) -> Iterator[BaseRoute | _EffectiveRouteContext]: - yield from self._low_priority_routes - for route in self.routes: - if isinstance(route, _IncludedRouter): - yield from route.effective_low_priority_routes() - - def _match_low_priority( - self, scope: Scope - ) -> tuple[Match, Scope, BaseRoute | None, _EffectiveRouteContext | None]: - full: tuple[Scope, BaseRoute, _EffectiveRouteContext | None] | None = None - partial: tuple[Scope, BaseRoute, _EffectiveRouteContext | None] | None = None - for candidate in self._iter_low_priority_routes(): - route: BaseRoute - if isinstance(candidate, _EffectiveRouteContext): - route_context: _EffectiveRouteContext | None = candidate - original_route = candidate.original_route - if isinstance(original_route, APIRoute): - fastapi_scope = _get_fastapi_scope(scope) - previous_context = fastapi_scope.get( - _FASTAPI_EFFECTIVE_ROUTE_CONTEXT_KEY, _SCOPE_MISSING - ) - fastapi_scope[_FASTAPI_EFFECTIVE_ROUTE_CONTEXT_KEY] = route_context - try: - match, child_scope = original_route.matches(scope) - finally: - _restore_fastapi_scope_key( - scope, - _FASTAPI_EFFECTIVE_ROUTE_CONTEXT_KEY, - previous_context, - ) - route = original_route - else: - match, child_scope = candidate.matches(scope) - route = candidate.starlette_route or original_route - else: - route_context = None - match, child_scope = candidate.matches(scope) - route = candidate - if match == Match.FULL: - if full is None: - full = (child_scope, route, route_context) - elif match == Match.PARTIAL: - if partial is None: - partial = (child_scope, route, route_context) - if full is not None: - child_scope, route, route_context = full - return Match.FULL, child_scope, route, route_context - if partial is not None: - child_scope, route, route_context = partial - return Match.PARTIAL, child_scope, route, route_context - return Match.NONE, {}, None, None - - def route( - self, - path: str, - methods: Collection[str] | None = None, - name: str | None = None, - include_in_schema: bool = True, - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.add_route( - path, - func, - methods=methods, - name=name, - include_in_schema=include_in_schema, - ) - return func - - return decorator - - def add_api_route( - self, - path: str, - endpoint: Callable[..., Any], - *, - response_model: Any = Default(None), - status_code: int | None = None, - tags: list[str | Enum] | None = None, - dependencies: Sequence[params.Depends] | None = None, - summary: str | None = None, - description: str | None = None, - response_description: str = "Successful Response", - responses: dict[int | str, dict[str, Any]] | None = None, - deprecated: bool | None = None, - methods: set[str] | list[str] | None = None, - operation_id: str | None = None, - response_model_include: IncEx | None = None, - response_model_exclude: IncEx | None = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: type[Response] | DefaultPlaceholder = Default(JSONResponse), - name: str | None = None, - route_class_override: type[APIRoute] | None = None, - callbacks: list[BaseRoute] | None = None, - openapi_extra: dict[str, Any] | None = None, - generate_unique_id_function: Callable[[APIRoute], str] - | DefaultPlaceholder = Default(generate_unique_id), - strict_content_type: bool | DefaultPlaceholder = Default(True), - ) -> None: - route_class = route_class_override or self.route_class - responses = responses or {} - combined_responses = {**self.responses, **responses} - current_response_class = get_value_or_default( - response_class, self.default_response_class - ) - current_tags = self.tags.copy() - if tags: - current_tags.extend(tags) - current_dependencies = self.dependencies.copy() - if dependencies: - current_dependencies.extend(dependencies) - current_callbacks = self.callbacks.copy() - if callbacks: - current_callbacks.extend(callbacks) - current_generate_unique_id = get_value_or_default( - generate_unique_id_function, self.generate_unique_id_function - ) - route = route_class( - self.prefix + path, - endpoint=endpoint, - response_model=response_model, - status_code=status_code, - tags=current_tags, - dependencies=current_dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=combined_responses, - deprecated=deprecated or self.deprecated, - methods=methods, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema and self.include_in_schema, - response_class=current_response_class, - name=name, - dependency_overrides_provider=self.dependency_overrides_provider, - callbacks=current_callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=current_generate_unique_id, - strict_content_type=get_value_or_default( - strict_content_type, self.strict_content_type - ), - ) - self.routes.append(route) - self._mark_routes_changed() - - def api_route( - self, - path: str, - *, - response_model: Any = Default(None), - status_code: int | None = None, - tags: list[str | Enum] | None = None, - dependencies: Sequence[params.Depends] | None = None, - summary: str | None = None, - description: str | None = None, - response_description: str = "Successful Response", - responses: dict[int | str, dict[str, Any]] | None = None, - deprecated: bool | None = None, - methods: list[str] | None = None, - operation_id: str | None = None, - response_model_include: IncEx | None = None, - response_model_exclude: IncEx | None = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: type[Response] = Default(JSONResponse), - name: str | None = None, - callbacks: list[BaseRoute] | None = None, - openapi_extra: dict[str, Any] | None = None, - generate_unique_id_function: Callable[[APIRoute], str] = Default( - generate_unique_id - ), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.add_api_route( - path, - func, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=methods, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - return func - - return decorator - - def add_api_websocket_route( - self, - path: str, - endpoint: Callable[..., Any], - name: str | None = None, - *, - dependencies: Sequence[params.Depends] | None = None, - ) -> None: - current_dependencies = self.dependencies.copy() - if dependencies: - current_dependencies.extend(dependencies) - - route = APIWebSocketRoute( - self.prefix + path, - endpoint=endpoint, - name=name, - dependencies=current_dependencies, - dependency_overrides_provider=self.dependency_overrides_provider, - ) - self.routes.append(route) - self._mark_routes_changed() - - def websocket( - self, - path: Annotated[ - str, - Doc( - """ - WebSocket path. - """ - ), - ], - name: Annotated[ - str | None, - Doc( - """ - A name for the WebSocket. Only used internally. - """ - ), - ] = None, - *, - dependencies: Annotated[ - Sequence[params.Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be used for this - WebSocket. - - Read more about it in the - [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/). - """ - ), - ] = None, - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Decorate a WebSocket function. - - Read more about it in the - [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/). - - **Example** - - ## Example - - ```python - from fastapi import APIRouter, FastAPI, WebSocket - - app = FastAPI() - router = APIRouter() - - @router.websocket("/ws") - async def websocket_endpoint(websocket: WebSocket): - await websocket.accept() - while True: - data = await websocket.receive_text() - await websocket.send_text(f"Message text was: {data}") - - app.include_router(router) - ``` - """ - - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.add_api_websocket_route( - path, func, name=name, dependencies=dependencies - ) - return func - - return decorator - - def websocket_route( - self, path: str, name: str | None = None - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.add_websocket_route(path, func, name=name) - return func - - return decorator - - def include_router( - self, - router: Annotated["APIRouter", Doc("The `APIRouter` to include.")], - *, - prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "", - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to all the *path operations* in this - router. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[params.Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to all the - *path operations* in this router. - - Read more about it in the - [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). - """ - ), - ] = None, - default_response_class: Annotated[ - type[Response], - Doc( - """ - The default response class to be used. - - Read more in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class). - """ - ), - ] = Default(JSONResponse), - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses to be shown in OpenAPI. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/). - - And in the - [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - OpenAPI callbacks that should apply to all *path operations* in this - router. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark all *path operations* in this router as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include (or not) all the *path operations* in this router in the - generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = True, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> None: - """ - Include another `APIRouter` in the same current `APIRouter`. - - Read more about it in the - [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/). - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - - app = FastAPI() - internal_router = APIRouter() - users_router = APIRouter() - - @users_router.get("/users/") - def read_users(): - return [{"name": "Rick"}, {"name": "Morty"}] - - internal_router.include_router(users_router) - app.include_router(internal_router) - ``` - """ - assert self is not router, ( - "Cannot include the same APIRouter instance into itself. " - "Did you mean to include a different router?" - ) - assert not router._contains_router(self), ( - "Cannot include an APIRouter instance that already includes this router. " - "Did you mean to include a different router?" - ) - if prefix: - assert prefix.startswith("/"), "A path prefix must start with '/'" - assert not prefix.endswith("/"), ( - "A path prefix must not end with '/', as the routes will start with '/'" - ) - else: - for route, route_context in _iter_routes_with_context(router.routes): - if route_context is None: - path = getattr(route, "path", None) - name = getattr(route, "name", "unknown") - elif route_context.starlette_route is not None: - path = getattr(route_context.starlette_route, "path", None) - name = getattr(route_context.starlette_route, "name", "unknown") - else: - path = route_context.path - name = route_context.name - if path is not None and not path: - raise FastAPIError( - f"Prefix and path cannot be both empty (path operation: {name})" - ) - include_context = _RouterIncludeContext.for_include( - parent_router=self, - included_router=router, - prefix=prefix, - tags=tags, - dependencies=dependencies, - default_response_class=default_response_class, - responses=responses, - callbacks=callbacks, - deprecated=deprecated, - include_in_schema=include_in_schema, - generate_unique_id_function=generate_unique_id_function, - ) - self.routes.append( - _IncludedRouter(original_router=router, include_context=include_context) - ) - self._mark_routes_changed() - for handler in router.on_startup: - self.add_event_handler("startup", handler) - for handler in router.on_shutdown: - self.add_event_handler("shutdown", handler) - self.lifespan_context = _merge_lifespan_context( - self.lifespan_context, - router.lifespan_context, - ) - - def get( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - int | None, - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[params.Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - str | None, - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - str | None, - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - str | None, - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP GET operation. - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - - app = FastAPI() - router = APIRouter() - - @router.get("/items/") - def read_items(): - return [{"name": "Empanada"}, {"name": "Arepa"}] - - app.include_router(router) - ``` - """ - return self.api_route( - path=path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=["GET"], - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def put( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - int | None, - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[params.Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - str | None, - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - str | None, - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - str | None, - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP PUT operation. - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - from pydantic import BaseModel - - class Item(BaseModel): - name: str - description: str | None = None - - app = FastAPI() - router = APIRouter() - - @router.put("/items/{item_id}") - def replace_item(item_id: str, item: Item): - return {"message": "Item replaced", "id": item_id} - - app.include_router(router) - ``` - """ - return self.api_route( - path=path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=["PUT"], - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def post( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - int | None, - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[params.Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - str | None, - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - str | None, - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - str | None, - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP POST operation. - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - from pydantic import BaseModel - - class Item(BaseModel): - name: str - description: str | None = None - - app = FastAPI() - router = APIRouter() - - @router.post("/items/") - def create_item(item: Item): - return {"message": "Item created"} - - app.include_router(router) - ``` - """ - return self.api_route( - path=path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=["POST"], - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def delete( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - int | None, - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[params.Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - str | None, - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - str | None, - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - str | None, - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP DELETE operation. - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - - app = FastAPI() - router = APIRouter() - - @router.delete("/items/{item_id}") - def delete_item(item_id: str): - return {"message": "Item deleted"} - - app.include_router(router) - ``` - """ - return self.api_route( - path=path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=["DELETE"], - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def options( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - int | None, - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[params.Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - str | None, - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - str | None, - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - str | None, - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP OPTIONS operation. - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - - app = FastAPI() - router = APIRouter() - - @router.options("/items/") - def get_item_options(): - return {"additions": ["Aji", "Guacamole"]} - - app.include_router(router) - ``` - """ - return self.api_route( - path=path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=["OPTIONS"], - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def head( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - int | None, - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[params.Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - str | None, - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - str | None, - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - str | None, - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP HEAD operation. - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - from pydantic import BaseModel - - class Item(BaseModel): - name: str - description: str | None = None - - app = FastAPI() - router = APIRouter() - - @router.head("/items/", status_code=204) - def get_items_headers(response: Response): - response.headers["X-Cat-Dog"] = "Alone in the world" - - app.include_router(router) - ``` - """ - return self.api_route( - path=path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=["HEAD"], - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def patch( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - int | None, - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[params.Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - str | None, - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - str | None, - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - str | None, - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP PATCH operation. - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - from pydantic import BaseModel - - class Item(BaseModel): - name: str - description: str | None = None - - app = FastAPI() - router = APIRouter() - - @router.patch("/items/") - def update_item(item: Item): - return {"message": "Item updated in place"} - - app.include_router(router) - ``` - """ - return self.api_route( - path=path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=["PATCH"], - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def trace( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - int | None, - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - list[str | Enum] | None, - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Sequence[params.Depends] | None, - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - str | None, - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - dict[int | str, dict[str, Any]] | None, - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - bool | None, - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - str | None, - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - IncEx | None, - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - str | None, - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - list[BaseRoute] | None, - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - dict[str, Any] | None, - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP TRACE operation. - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - from pydantic import BaseModel - - class Item(BaseModel): - name: str - description: str | None = None - - app = FastAPI() - router = APIRouter() - - @router.trace("/items/{item_id}") - def trace_item(item_id: str): - return None - - app.include_router(router) - ``` - """ - return self.api_route( - path=path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=["TRACE"], - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - # TODO: remove this once the lifespan (or alternative) interface is improved - async def _startup(self) -> None: - """ - Run any `.on_startup` event handlers. - - This method is kept for backward compatibility after Starlette removed - support for on_startup/on_shutdown handlers. - - Ref: https://github.com/Kludex/starlette/pull/3117 - """ - for handler in self.on_startup: - if is_async_callable(handler): - await handler() - else: - handler() - - # TODO: remove this once the lifespan (or alternative) interface is improved - async def _shutdown(self) -> None: - """ - Run any `.on_shutdown` event handlers. - - This method is kept for backward compatibility after Starlette removed - support for on_startup/on_shutdown handlers. - - Ref: https://github.com/Kludex/starlette/pull/3117 - """ - for handler in self.on_shutdown: - if is_async_callable(handler): - await handler() - else: - handler() - - # TODO: remove this once the lifespan (or alternative) interface is improved - def add_event_handler( - self, - event_type: str, - func: Callable[[], Any], - ) -> None: - """ - Add an event handler function for startup or shutdown. - - This method is kept for backward compatibility after Starlette removed - support for on_startup/on_shutdown handlers. - - Ref: https://github.com/Kludex/starlette/pull/3117 - """ - assert event_type in ("startup", "shutdown") - if event_type == "startup": - self.on_startup.append(func) - else: - self.on_shutdown.append(func) - - @deprecated( - """ - on_event is deprecated, use lifespan event handlers instead. - - Read more about it in the - [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/). - """ - ) - def on_event( - self, - event_type: Annotated[ - str, - Doc( - """ - The type of event. `startup` or `shutdown`. - """ - ), - ], - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add an event handler for the router. - - `on_event` is deprecated, use `lifespan` event handlers instead. - - Read more about it in the - [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/#alternative-events-deprecated). - """ - - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.add_event_handler(event_type, func) - return func - - return decorator diff --git a/server/venv/Lib/site-packages/fastapi/security/__init__.py b/server/venv/Lib/site-packages/fastapi/security/__init__.py deleted file mode 100644 index 3aa6bf2..0000000 --- a/server/venv/Lib/site-packages/fastapi/security/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -from .api_key import APIKeyCookie as APIKeyCookie -from .api_key import APIKeyHeader as APIKeyHeader -from .api_key import APIKeyQuery as APIKeyQuery -from .http import HTTPAuthorizationCredentials as HTTPAuthorizationCredentials -from .http import HTTPBasic as HTTPBasic -from .http import HTTPBasicCredentials as HTTPBasicCredentials -from .http import HTTPBearer as HTTPBearer -from .http import HTTPDigest as HTTPDigest -from .oauth2 import OAuth2 as OAuth2 -from .oauth2 import OAuth2AuthorizationCodeBearer as OAuth2AuthorizationCodeBearer -from .oauth2 import OAuth2PasswordBearer as OAuth2PasswordBearer -from .oauth2 import OAuth2PasswordRequestForm as OAuth2PasswordRequestForm -from .oauth2 import OAuth2PasswordRequestFormStrict as OAuth2PasswordRequestFormStrict -from .oauth2 import SecurityScopes as SecurityScopes -from .open_id_connect_url import OpenIdConnect as OpenIdConnect diff --git a/server/venv/Lib/site-packages/fastapi/security/api_key.py b/server/venv/Lib/site-packages/fastapi/security/api_key.py deleted file mode 100644 index 83a4585..0000000 --- a/server/venv/Lib/site-packages/fastapi/security/api_key.py +++ /dev/null @@ -1,320 +0,0 @@ -from typing import Annotated - -from annotated_doc import Doc -from fastapi.openapi.models import APIKey, APIKeyIn -from fastapi.security.base import SecurityBase -from starlette.exceptions import HTTPException -from starlette.requests import Request -from starlette.status import HTTP_401_UNAUTHORIZED - - -class APIKeyBase(SecurityBase): - model: APIKey - - def __init__( - self, - location: APIKeyIn, - name: str, - description: str | None, - scheme_name: str | None, - auto_error: bool, - ): - self.auto_error = auto_error - - self.model: APIKey = APIKey( - **{"in": location}, # ty: ignore[invalid-argument-type] - name=name, - description=description, - ) - self.scheme_name = scheme_name or self.__class__.__name__ - - def make_not_authenticated_error(self) -> HTTPException: - """ - The WWW-Authenticate header is not standardized for API Key authentication but - the HTTP specification requires that an error of 401 "Unauthorized" must - include a WWW-Authenticate header. - - Ref: https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized - - For this, this method sends a custom challenge `APIKey`. - """ - return HTTPException( - status_code=HTTP_401_UNAUTHORIZED, - detail="Not authenticated", - headers={"WWW-Authenticate": "APIKey"}, - ) - - def check_api_key(self, api_key: str | None) -> str | None: - if not api_key: - if self.auto_error: - raise self.make_not_authenticated_error() - return None - return api_key - - -class APIKeyQuery(APIKeyBase): - """ - API key authentication using a query parameter. - - This defines the name of the query parameter that should be provided in the request - with the API key and integrates that into the OpenAPI documentation. It extracts - the key value sent in the query parameter automatically and provides it as the - dependency result. But it doesn't define how to send that API key to the client. - - ## Usage - - Create an instance object and use that object as the dependency in `Depends()`. - - The dependency result will be a string containing the key value. - - ## Example - - ```python - from fastapi import Depends, FastAPI - from fastapi.security import APIKeyQuery - - app = FastAPI() - - query_scheme = APIKeyQuery(name="api_key") - - - @app.get("/items/") - async def read_items(api_key: str = Depends(query_scheme)): - return {"api_key": api_key} - ``` - """ - - def __init__( - self, - *, - name: Annotated[ - str, - Doc("Query parameter name."), - ], - scheme_name: Annotated[ - str | None, - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if the query parameter is not provided, `APIKeyQuery` will - automatically cancel the request and send the client an error. - - If `auto_error` is set to `False`, when the query parameter is not - available, instead of erroring out, the dependency result will be - `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, in a query - parameter or in an HTTP Bearer token). - """ - ), - ] = True, - ): - super().__init__( - location=APIKeyIn.query, - name=name, - scheme_name=scheme_name, - description=description, - auto_error=auto_error, - ) - - async def __call__(self, request: Request) -> str | None: - api_key = request.query_params.get(self.model.name) - return self.check_api_key(api_key) - - -class APIKeyHeader(APIKeyBase): - """ - API key authentication using a header. - - This defines the name of the header that should be provided in the request with - the API key and integrates that into the OpenAPI documentation. It extracts - the key value sent in the header automatically and provides it as the dependency - result. But it doesn't define how to send that key to the client. - - ## Usage - - Create an instance object and use that object as the dependency in `Depends()`. - - The dependency result will be a string containing the key value. - - ## Example - - ```python - from fastapi import Depends, FastAPI - from fastapi.security import APIKeyHeader - - app = FastAPI() - - header_scheme = APIKeyHeader(name="x-key") - - - @app.get("/items/") - async def read_items(key: str = Depends(header_scheme)): - return {"key": key} - ``` - """ - - def __init__( - self, - *, - name: Annotated[str, Doc("Header name.")], - scheme_name: Annotated[ - str | None, - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if the header is not provided, `APIKeyHeader` will - automatically cancel the request and send the client an error. - - If `auto_error` is set to `False`, when the header is not available, - instead of erroring out, the dependency result will be `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, in a header or - in an HTTP Bearer token). - """ - ), - ] = True, - ): - super().__init__( - location=APIKeyIn.header, - name=name, - scheme_name=scheme_name, - description=description, - auto_error=auto_error, - ) - - async def __call__(self, request: Request) -> str | None: - api_key = request.headers.get(self.model.name) - return self.check_api_key(api_key) - - -class APIKeyCookie(APIKeyBase): - """ - API key authentication using a cookie. - - This defines the name of the cookie that should be provided in the request with - the API key and integrates that into the OpenAPI documentation. It extracts - the key value sent in the cookie automatically and provides it as the dependency - result. But it doesn't define how to set that cookie. - - ## Usage - - Create an instance object and use that object as the dependency in `Depends()`. - - The dependency result will be a string containing the key value. - - ## Example - - ```python - from fastapi import Depends, FastAPI - from fastapi.security import APIKeyCookie - - app = FastAPI() - - cookie_scheme = APIKeyCookie(name="session") - - - @app.get("/items/") - async def read_items(session: str = Depends(cookie_scheme)): - return {"session": session} - ``` - """ - - def __init__( - self, - *, - name: Annotated[str, Doc("Cookie name.")], - scheme_name: Annotated[ - str | None, - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if the cookie is not provided, `APIKeyCookie` will - automatically cancel the request and send the client an error. - - If `auto_error` is set to `False`, when the cookie is not available, - instead of erroring out, the dependency result will be `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, in a cookie or - in an HTTP Bearer token). - """ - ), - ] = True, - ): - super().__init__( - location=APIKeyIn.cookie, - name=name, - scheme_name=scheme_name, - description=description, - auto_error=auto_error, - ) - - async def __call__(self, request: Request) -> str | None: - api_key = request.cookies.get(self.model.name) - return self.check_api_key(api_key) diff --git a/server/venv/Lib/site-packages/fastapi/security/base.py b/server/venv/Lib/site-packages/fastapi/security/base.py deleted file mode 100644 index c43555d..0000000 --- a/server/venv/Lib/site-packages/fastapi/security/base.py +++ /dev/null @@ -1,6 +0,0 @@ -from fastapi.openapi.models import SecurityBase as SecurityBaseModel - - -class SecurityBase: - model: SecurityBaseModel - scheme_name: str diff --git a/server/venv/Lib/site-packages/fastapi/security/http.py b/server/venv/Lib/site-packages/fastapi/security/http.py deleted file mode 100644 index a32948e..0000000 --- a/server/venv/Lib/site-packages/fastapi/security/http.py +++ /dev/null @@ -1,417 +0,0 @@ -import binascii -from base64 import b64decode -from typing import Annotated - -from annotated_doc import Doc -from fastapi.exceptions import HTTPException -from fastapi.openapi.models import HTTPBase as HTTPBaseModel -from fastapi.openapi.models import HTTPBearer as HTTPBearerModel -from fastapi.security.base import SecurityBase -from fastapi.security.utils import get_authorization_scheme_param -from pydantic import BaseModel -from starlette.requests import Request -from starlette.status import HTTP_401_UNAUTHORIZED - - -class HTTPBasicCredentials(BaseModel): - """ - The HTTP Basic credentials given as the result of using `HTTPBasic` in a - dependency. - - Read more about it in the - [FastAPI docs for HTTP Basic Auth](https://fastapi.tiangolo.com/advanced/security/http-basic-auth/). - """ - - username: Annotated[str, Doc("The HTTP Basic username.")] - password: Annotated[str, Doc("The HTTP Basic password.")] - - -class HTTPAuthorizationCredentials(BaseModel): - """ - The HTTP authorization credentials in the result of using `HTTPBearer` or - `HTTPDigest` in a dependency. - - The HTTP authorization header value is split by the first space. - - The first part is the `scheme`, the second part is the `credentials`. - - For example, in an HTTP Bearer token scheme, the client will send a header - like: - - ``` - Authorization: Bearer deadbeef12346 - ``` - - In this case: - - * `scheme` will have the value `"Bearer"` - * `credentials` will have the value `"deadbeef12346"` - """ - - scheme: Annotated[ - str, - Doc( - """ - The HTTP authorization scheme extracted from the header value. - """ - ), - ] - credentials: Annotated[ - str, - Doc( - """ - The HTTP authorization credentials extracted from the header value. - """ - ), - ] - - -class HTTPBase(SecurityBase): - model: HTTPBaseModel - - def __init__( - self, - *, - scheme: str, - scheme_name: str | None = None, - description: str | None = None, - auto_error: bool = True, - ): - self.model = HTTPBaseModel(scheme=scheme, description=description) - self.scheme_name = scheme_name or self.__class__.__name__ - self.auto_error = auto_error - - def make_authenticate_headers(self) -> dict[str, str]: - return {"WWW-Authenticate": f"{self.model.scheme.title()}"} - - def make_not_authenticated_error(self) -> HTTPException: - return HTTPException( - status_code=HTTP_401_UNAUTHORIZED, - detail="Not authenticated", - headers=self.make_authenticate_headers(), - ) - - async def __call__(self, request: Request) -> HTTPAuthorizationCredentials | None: - authorization = request.headers.get("Authorization") - scheme, credentials = get_authorization_scheme_param(authorization) - if not (authorization and scheme and credentials): - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None - return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials) - - -class HTTPBasic(HTTPBase): - """ - HTTP Basic authentication. - - Ref: https://datatracker.ietf.org/doc/html/rfc7617 - - ## Usage - - Create an instance object and use that object as the dependency in `Depends()`. - - The dependency result will be an `HTTPBasicCredentials` object containing the - `username` and the `password`. - - Read more about it in the - [FastAPI docs for HTTP Basic Auth](https://fastapi.tiangolo.com/advanced/security/http-basic-auth/). - - ## Example - - ```python - from typing import Annotated - - from fastapi import Depends, FastAPI - from fastapi.security import HTTPBasic, HTTPBasicCredentials - - app = FastAPI() - - security = HTTPBasic() - - - @app.get("/users/me") - def read_current_user(credentials: Annotated[HTTPBasicCredentials, Depends(security)]): - return {"username": credentials.username, "password": credentials.password} - ``` - """ - - def __init__( - self, - *, - scheme_name: Annotated[ - str | None, - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - realm: Annotated[ - str | None, - Doc( - """ - HTTP Basic authentication realm. - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if the HTTP Basic authentication is not provided (a - header), `HTTPBasic` will automatically cancel the request and send the - client an error. - - If `auto_error` is set to `False`, when the HTTP Basic authentication - is not available, instead of erroring out, the dependency result will - be `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, in HTTP Basic - authentication or in an HTTP Bearer token). - """ - ), - ] = True, - ): - self.model = HTTPBaseModel(scheme="basic", description=description) - self.scheme_name = scheme_name or self.__class__.__name__ - self.realm = realm - self.auto_error = auto_error - - def make_authenticate_headers(self) -> dict[str, str]: - if self.realm: - return {"WWW-Authenticate": f'Basic realm="{self.realm}"'} - return {"WWW-Authenticate": "Basic"} - - async def __call__( # type: ignore - self, request: Request - ) -> HTTPBasicCredentials | None: - authorization = request.headers.get("Authorization") - scheme, param = get_authorization_scheme_param(authorization) - if not authorization or scheme.lower() != "basic": - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None - try: - data = b64decode(param).decode("ascii") - except (ValueError, UnicodeDecodeError, binascii.Error) as e: - raise self.make_not_authenticated_error() from e - username, separator, password = data.partition(":") - if not separator: - raise self.make_not_authenticated_error() - return HTTPBasicCredentials(username=username, password=password) - - -class HTTPBearer(HTTPBase): - """ - HTTP Bearer token authentication. - - ## Usage - - Create an instance object and use that object as the dependency in `Depends()`. - - The dependency result will be an `HTTPAuthorizationCredentials` object containing - the `scheme` and the `credentials`. - - ## Example - - ```python - from typing import Annotated - - from fastapi import Depends, FastAPI - from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer - - app = FastAPI() - - security = HTTPBearer() - - - @app.get("/users/me") - def read_current_user( - credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)] - ): - return {"scheme": credentials.scheme, "credentials": credentials.credentials} - ``` - """ - - def __init__( - self, - *, - bearerFormat: Annotated[str | None, Doc("Bearer token format.")] = None, - scheme_name: Annotated[ - str | None, - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if the HTTP Bearer token is not provided (in an - `Authorization` header), `HTTPBearer` will automatically cancel the - request and send the client an error. - - If `auto_error` is set to `False`, when the HTTP Bearer token - is not available, instead of erroring out, the dependency result will - be `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, in an HTTP - Bearer token or in a cookie). - """ - ), - ] = True, - ): - self.model = HTTPBearerModel(bearerFormat=bearerFormat, description=description) - self.scheme_name = scheme_name or self.__class__.__name__ - self.auto_error = auto_error - - async def __call__(self, request: Request) -> HTTPAuthorizationCredentials | None: - authorization = request.headers.get("Authorization") - scheme, credentials = get_authorization_scheme_param(authorization) - if not (authorization and scheme and credentials): - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None - if scheme.lower() != "bearer": - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None - return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials) - - -class HTTPDigest(HTTPBase): - """ - HTTP Digest authentication. - - **Warning**: this is only a stub to connect the components with OpenAPI in FastAPI, - but it doesn't implement the full Digest scheme, you would need to subclass it - and implement it in your code. - - Ref: https://datatracker.ietf.org/doc/html/rfc7616 - - ## Usage - - Create an instance object and use that object as the dependency in `Depends()`. - - The dependency result will be an `HTTPAuthorizationCredentials` object containing - the `scheme` and the `credentials`. - - ## Example - - ```python - from typing import Annotated - - from fastapi import Depends, FastAPI - from fastapi.security import HTTPAuthorizationCredentials, HTTPDigest - - app = FastAPI() - - security = HTTPDigest() - - - @app.get("/users/me") - def read_current_user( - credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)] - ): - return {"scheme": credentials.scheme, "credentials": credentials.credentials} - ``` - """ - - def __init__( - self, - *, - scheme_name: Annotated[ - str | None, - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if the HTTP Digest is not provided, `HTTPDigest` will - automatically cancel the request and send the client an error. - - If `auto_error` is set to `False`, when the HTTP Digest is not - available, instead of erroring out, the dependency result will - be `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, in HTTP - Digest or in a cookie). - """ - ), - ] = True, - ): - self.model = HTTPBaseModel(scheme="digest", description=description) - self.scheme_name = scheme_name or self.__class__.__name__ - self.auto_error = auto_error - - async def __call__(self, request: Request) -> HTTPAuthorizationCredentials | None: - authorization = request.headers.get("Authorization") - scheme, credentials = get_authorization_scheme_param(authorization) - if not (authorization and scheme and credentials): - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None - if scheme.lower() != "digest": - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None - return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials) diff --git a/server/venv/Lib/site-packages/fastapi/security/oauth2.py b/server/venv/Lib/site-packages/fastapi/security/oauth2.py deleted file mode 100644 index 3fd9e41..0000000 --- a/server/venv/Lib/site-packages/fastapi/security/oauth2.py +++ /dev/null @@ -1,693 +0,0 @@ -from typing import Annotated, Any, cast - -from annotated_doc import Doc -from fastapi.exceptions import HTTPException -from fastapi.openapi.models import OAuth2 as OAuth2Model -from fastapi.openapi.models import OAuthFlows as OAuthFlowsModel -from fastapi.param_functions import Form -from fastapi.security.base import SecurityBase -from fastapi.security.utils import get_authorization_scheme_param -from starlette.requests import Request -from starlette.status import HTTP_401_UNAUTHORIZED - - -class OAuth2PasswordRequestForm: - """ - This is a dependency class to collect the `username` and `password` as form data - for an OAuth2 password flow. - - The OAuth2 specification dictates that for a password flow the data should be - collected using form data (instead of JSON) and that it should have the specific - fields `username` and `password`. - - All the initialization parameters are extracted from the request. - - Read more about it in the - [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). - - ## Example - - ```python - from typing import Annotated - - from fastapi import Depends, FastAPI - from fastapi.security import OAuth2PasswordRequestForm - - app = FastAPI() - - - @app.post("/login") - def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]): - data = {} - data["scopes"] = [] - for scope in form_data.scopes: - data["scopes"].append(scope) - if form_data.client_id: - data["client_id"] = form_data.client_id - if form_data.client_secret: - data["client_secret"] = form_data.client_secret - return data - ``` - - Note that for OAuth2 the scope `items:read` is a single scope in an opaque string. - You could have custom internal logic to separate it by colon characters (`:`) or - similar, and get the two parts `items` and `read`. Many applications do that to - group and organize permissions, you could do it as well in your application, just - know that it is application specific, it's not part of the specification. - """ - - def __init__( - self, - *, - grant_type: Annotated[ - str | None, - Form(pattern="^password$"), - Doc( - """ - The OAuth2 spec says it is required and MUST be the fixed string - "password". Nevertheless, this dependency class is permissive and - allows not passing it. If you want to enforce it, use instead the - `OAuth2PasswordRequestFormStrict` dependency. - - Read more about it in the - [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). - """ - ), - ] = None, - username: Annotated[ - str, - Form(), - Doc( - """ - `username` string. The OAuth2 spec requires the exact field name - `username`. - - Read more about it in the - [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). - """ - ), - ], - password: Annotated[ - str, - Form(json_schema_extra={"format": "password"}), - Doc( - """ - `password` string. The OAuth2 spec requires the exact field name - `password`. - - Read more about it in the - [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). - """ - ), - ], - scope: Annotated[ - str, - Form(), - Doc( - """ - A single string with actually several scopes separated by spaces. Each - scope is also a string. - - For example, a single string with: - - ```python - "items:read items:write users:read profile openid" - ```` - - would represent the scopes: - - * `items:read` - * `items:write` - * `users:read` - * `profile` - * `openid` - - Read more about it in the - [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). - """ - ), - ] = "", - client_id: Annotated[ - str | None, - Form(), - Doc( - """ - If there's a `client_id`, it can be sent as part of the form fields. - But the OAuth2 specification recommends sending the `client_id` and - `client_secret` (if any) using HTTP Basic auth. - """ - ), - ] = None, - client_secret: Annotated[ - str | None, - Form(json_schema_extra={"format": "password"}), - Doc( - """ - If there's a `client_secret` (and a `client_id`), they can be sent - as part of the form fields. But the OAuth2 specification recommends - sending the `client_id` and `client_secret` (if any) using HTTP Basic - auth. - """ - ), - ] = None, - ): - self.grant_type = grant_type - self.username = username - self.password = password - self.scopes = scope.split() - self.client_id = client_id - self.client_secret = client_secret - - -class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm): - """ - This is a dependency class to collect the `username` and `password` as form data - for an OAuth2 password flow. - - The OAuth2 specification dictates that for a password flow the data should be - collected using form data (instead of JSON) and that it should have the specific - fields `username` and `password`. - - All the initialization parameters are extracted from the request. - - The only difference between `OAuth2PasswordRequestFormStrict` and - `OAuth2PasswordRequestForm` is that `OAuth2PasswordRequestFormStrict` requires the - client to send the form field `grant_type` with the value `"password"`, which - is required in the OAuth2 specification (it seems that for no particular reason), - while for `OAuth2PasswordRequestForm` `grant_type` is optional. - - Read more about it in the - [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). - - ## Example - - ```python - from typing import Annotated - - from fastapi import Depends, FastAPI - from fastapi.security import OAuth2PasswordRequestForm - - app = FastAPI() - - - @app.post("/login") - def login(form_data: Annotated[OAuth2PasswordRequestFormStrict, Depends()]): - data = {} - data["scopes"] = [] - for scope in form_data.scopes: - data["scopes"].append(scope) - if form_data.client_id: - data["client_id"] = form_data.client_id - if form_data.client_secret: - data["client_secret"] = form_data.client_secret - return data - ``` - - Note that for OAuth2 the scope `items:read` is a single scope in an opaque string. - You could have custom internal logic to separate it by colon characters (`:`) or - similar, and get the two parts `items` and `read`. Many applications do that to - group and organize permissions, you could do it as well in your application, just - know that it is application specific, it's not part of the specification. - - - grant_type: the OAuth2 spec says it is required and MUST be the fixed string "password". - This dependency is strict about it. If you want to be permissive, use instead the - OAuth2PasswordRequestForm dependency class. - username: username string. The OAuth2 spec requires the exact field name "username". - password: password string. The OAuth2 spec requires the exact field name "password". - scope: Optional string. Several scopes (each one a string) separated by spaces. E.g. - "items:read items:write users:read profile openid" - client_id: optional string. OAuth2 recommends sending the client_id and client_secret (if any) - using HTTP Basic auth, as: client_id:client_secret - client_secret: optional string. OAuth2 recommends sending the client_id and client_secret (if any) - using HTTP Basic auth, as: client_id:client_secret - """ - - def __init__( - self, - grant_type: Annotated[ - str, - Form(pattern="^password$"), - Doc( - """ - The OAuth2 spec says it is required and MUST be the fixed string - "password". This dependency is strict about it. If you want to be - permissive, use instead the `OAuth2PasswordRequestForm` dependency - class. - - Read more about it in the - [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). - """ - ), - ], - username: Annotated[ - str, - Form(), - Doc( - """ - `username` string. The OAuth2 spec requires the exact field name - `username`. - - Read more about it in the - [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). - """ - ), - ], - password: Annotated[ - str, - Form(), - Doc( - """ - `password` string. The OAuth2 spec requires the exact field name - `password`. - - Read more about it in the - [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). - """ - ), - ], - scope: Annotated[ - str, - Form(), - Doc( - """ - A single string with actually several scopes separated by spaces. Each - scope is also a string. - - For example, a single string with: - - ```python - "items:read items:write users:read profile openid" - ```` - - would represent the scopes: - - * `items:read` - * `items:write` - * `users:read` - * `profile` - * `openid` - - Read more about it in the - [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). - """ - ), - ] = "", - client_id: Annotated[ - str | None, - Form(), - Doc( - """ - If there's a `client_id`, it can be sent as part of the form fields. - But the OAuth2 specification recommends sending the `client_id` and - `client_secret` (if any) using HTTP Basic auth. - """ - ), - ] = None, - client_secret: Annotated[ - str | None, - Form(), - Doc( - """ - If there's a `client_secret` (and a `client_id`), they can be sent - as part of the form fields. But the OAuth2 specification recommends - sending the `client_id` and `client_secret` (if any) using HTTP Basic - auth. - """ - ), - ] = None, - ): - super().__init__( - grant_type=grant_type, - username=username, - password=password, - scope=scope, - client_id=client_id, - client_secret=client_secret, - ) - - -class OAuth2(SecurityBase): - """ - This is the base class for OAuth2 authentication, an instance of it would be used - as a dependency. All other OAuth2 classes inherit from it and customize it for - each OAuth2 flow. - - You normally would not create a new class inheriting from it but use one of the - existing subclasses, and maybe compose them if you want to support multiple flows. - - Read more about it in the - [FastAPI docs for Security](https://fastapi.tiangolo.com/tutorial/security/). - """ - - def __init__( - self, - *, - flows: Annotated[ - OAuthFlowsModel | dict[str, dict[str, Any]], - Doc( - """ - The dictionary of OAuth2 flows. - """ - ), - ] = OAuthFlowsModel(), - scheme_name: Annotated[ - str | None, - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if no HTTP Authorization header is provided, required for - OAuth2 authentication, it will automatically cancel the request and - send the client an error. - - If `auto_error` is set to `False`, when the HTTP Authorization header - is not available, instead of erroring out, the dependency result will - be `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, with OAuth2 - or in a cookie). - """ - ), - ] = True, - ): - self.model = OAuth2Model( - flows=cast(OAuthFlowsModel, flows), description=description - ) - self.scheme_name = scheme_name or self.__class__.__name__ - self.auto_error = auto_error - - def make_not_authenticated_error(self) -> HTTPException: - """ - The OAuth 2 specification doesn't define the challenge that should be used, - because a `Bearer` token is not really the only option to authenticate. - - But declaring any other authentication challenge would be application-specific - as it's not defined in the specification. - - For practical reasons, this method uses the `Bearer` challenge by default, as - it's probably the most common one. - - If you are implementing an OAuth2 authentication scheme other than the provided - ones in FastAPI (based on bearer tokens), you might want to override this. - - Ref: https://datatracker.ietf.org/doc/html/rfc6749 - """ - return HTTPException( - status_code=HTTP_401_UNAUTHORIZED, - detail="Not authenticated", - headers={"WWW-Authenticate": "Bearer"}, - ) - - async def __call__(self, request: Request) -> str | None: - authorization = request.headers.get("Authorization") - if not authorization: - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None - return authorization - - -class OAuth2PasswordBearer(OAuth2): - """ - OAuth2 flow for authentication using a bearer token obtained with a password. - An instance of it would be used as a dependency. - - Read more about it in the - [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). - """ - - def __init__( - self, - tokenUrl: Annotated[ - str, - Doc( - """ - The URL to obtain the OAuth2 token. This would be the *path operation* - that has `OAuth2PasswordRequestForm` as a dependency. - - Read more about it in the - [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). - """ - ), - ], - scheme_name: Annotated[ - str | None, - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - scopes: Annotated[ - dict[str, str] | None, - Doc( - """ - The OAuth2 scopes that would be required by the *path operations* that - use this dependency. - - Read more about it in the - [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if no HTTP Authorization header is provided, required for - OAuth2 authentication, it will automatically cancel the request and - send the client an error. - - If `auto_error` is set to `False`, when the HTTP Authorization header - is not available, instead of erroring out, the dependency result will - be `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, with OAuth2 - or in a cookie). - """ - ), - ] = True, - refreshUrl: Annotated[ - str | None, - Doc( - """ - The URL to refresh the token and obtain a new one. - """ - ), - ] = None, - ): - if not scopes: - scopes = {} - flows = OAuthFlowsModel( - password=cast( - Any, - { - "tokenUrl": tokenUrl, - "refreshUrl": refreshUrl, - "scopes": scopes, - }, - ) - ) - super().__init__( - flows=flows, - scheme_name=scheme_name, - description=description, - auto_error=auto_error, - ) - - async def __call__(self, request: Request) -> str | None: - authorization = request.headers.get("Authorization") - scheme, param = get_authorization_scheme_param(authorization) - if not authorization or scheme.lower() != "bearer": - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None - return param - - -class OAuth2AuthorizationCodeBearer(OAuth2): - """ - OAuth2 flow for authentication using a bearer token obtained with an OAuth2 code - flow. An instance of it would be used as a dependency. - """ - - def __init__( - self, - authorizationUrl: str, - tokenUrl: Annotated[ - str, - Doc( - """ - The URL to obtain the OAuth2 token. - """ - ), - ], - refreshUrl: Annotated[ - str | None, - Doc( - """ - The URL to refresh the token and obtain a new one. - """ - ), - ] = None, - scheme_name: Annotated[ - str | None, - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - scopes: Annotated[ - dict[str, str] | None, - Doc( - """ - The OAuth2 scopes that would be required by the *path operations* that - use this dependency. - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if no HTTP Authorization header is provided, required for - OAuth2 authentication, it will automatically cancel the request and - send the client an error. - - If `auto_error` is set to `False`, when the HTTP Authorization header - is not available, instead of erroring out, the dependency result will - be `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, with OAuth2 - or in a cookie). - """ - ), - ] = True, - ): - if not scopes: - scopes = {} - flows = OAuthFlowsModel( - authorizationCode=cast( - Any, - { - "authorizationUrl": authorizationUrl, - "tokenUrl": tokenUrl, - "refreshUrl": refreshUrl, - "scopes": scopes, - }, - ) - ) - super().__init__( - flows=flows, - scheme_name=scheme_name, - description=description, - auto_error=auto_error, - ) - - async def __call__(self, request: Request) -> str | None: - authorization = request.headers.get("Authorization") - scheme, param = get_authorization_scheme_param(authorization) - if not authorization or scheme.lower() != "bearer": - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None # pragma: nocover - return param - - -class SecurityScopes: - """ - This is a special class that you can define in a parameter in a dependency to - obtain the OAuth2 scopes required by all the dependencies in the same chain. - - This way, multiple dependencies can have different scopes, even when used in the - same *path operation*. And with this, you can access all the scopes required in - all those dependencies in a single place. - - Read more about it in the - [FastAPI docs for OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/). - """ - - def __init__( - self, - scopes: Annotated[ - list[str] | None, - Doc( - """ - This will be filled by FastAPI. - """ - ), - ] = None, - ): - self.scopes: Annotated[ - list[str], - Doc( - """ - The list of all the scopes required by dependencies. - """ - ), - ] = scopes or [] - self.scope_str: Annotated[ - str, - Doc( - """ - All the scopes required by all the dependencies in a single string - separated by spaces, as defined in the OAuth2 specification. - """ - ), - ] = " ".join(self.scopes) diff --git a/server/venv/Lib/site-packages/fastapi/security/open_id_connect_url.py b/server/venv/Lib/site-packages/fastapi/security/open_id_connect_url.py deleted file mode 100644 index 125a819..0000000 --- a/server/venv/Lib/site-packages/fastapi/security/open_id_connect_url.py +++ /dev/null @@ -1,94 +0,0 @@ -from typing import Annotated - -from annotated_doc import Doc -from fastapi.openapi.models import OpenIdConnect as OpenIdConnectModel -from fastapi.security.base import SecurityBase -from starlette.exceptions import HTTPException -from starlette.requests import Request -from starlette.status import HTTP_401_UNAUTHORIZED - - -class OpenIdConnect(SecurityBase): - """ - OpenID Connect authentication class. An instance of it would be used as a - dependency. - - **Warning**: this is only a stub to connect the components with OpenAPI in FastAPI, - but it doesn't implement the full OpenIdConnect scheme, for example, it doesn't use - the OpenIDConnect URL. You would need to subclass it and implement it in your - code. - """ - - def __init__( - self, - *, - openIdConnectUrl: Annotated[ - str, - Doc( - """ - The OpenID Connect URL. - """ - ), - ], - scheme_name: Annotated[ - str | None, - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - description: Annotated[ - str | None, - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if no HTTP Authorization header is provided, required for - OpenID Connect authentication, it will automatically cancel the request - and send the client an error. - - If `auto_error` is set to `False`, when the HTTP Authorization header - is not available, instead of erroring out, the dependency result will - be `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, with OpenID - Connect or in a cookie). - """ - ), - ] = True, - ): - self.model = OpenIdConnectModel( - openIdConnectUrl=openIdConnectUrl, description=description - ) - self.scheme_name = scheme_name or self.__class__.__name__ - self.auto_error = auto_error - - def make_not_authenticated_error(self) -> HTTPException: - return HTTPException( - status_code=HTTP_401_UNAUTHORIZED, - detail="Not authenticated", - headers={"WWW-Authenticate": "Bearer"}, - ) - - async def __call__(self, request: Request) -> str | None: - authorization = request.headers.get("Authorization") - if not authorization: - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None - return authorization diff --git a/server/venv/Lib/site-packages/fastapi/security/utils.py b/server/venv/Lib/site-packages/fastapi/security/utils.py deleted file mode 100644 index 8ee66fd..0000000 --- a/server/venv/Lib/site-packages/fastapi/security/utils.py +++ /dev/null @@ -1,7 +0,0 @@ -def get_authorization_scheme_param( - authorization_header_value: str | None, -) -> tuple[str, str]: - if not authorization_header_value: - return "", "" - scheme, _, param = authorization_header_value.partition(" ") - return scheme, param.strip() diff --git a/server/venv/Lib/site-packages/fastapi/sse.py b/server/venv/Lib/site-packages/fastapi/sse.py deleted file mode 100644 index 1e2bd86..0000000 --- a/server/venv/Lib/site-packages/fastapi/sse.py +++ /dev/null @@ -1,235 +0,0 @@ -from typing import Annotated, Any - -from annotated_doc import Doc -from pydantic import AfterValidator, BaseModel, Field, model_validator -from starlette.responses import StreamingResponse - -# Canonical SSE event schema matching the OpenAPI 3.2 spec -# (Section 4.14.4 "Special Considerations for Server-Sent Events") -_SSE_EVENT_SCHEMA: dict[str, Any] = { - "type": "object", - "properties": { - "data": {"type": "string"}, - "event": {"type": "string"}, - "id": {"type": "string"}, - "retry": {"type": "integer", "minimum": 0}, - }, -} - - -class EventSourceResponse(StreamingResponse): - """Streaming response with `text/event-stream` media type. - - Use as `response_class=EventSourceResponse` on a *path operation* that uses `yield` - to enable Server Sent Events (SSE) responses. - - Works with **any HTTP method** (`GET`, `POST`, etc.), which makes it compatible - with protocols like MCP that stream SSE over `POST`. - - The actual encoding logic lives in the FastAPI routing layer. This class - serves mainly as a marker and sets the correct `Content-Type`. - """ - - media_type = "text/event-stream" - - -def _check_single_line(v: str | None, field_name: str) -> str | None: - if v is not None and ("\r" in v or "\n" in v): - raise ValueError(f"SSE '{field_name}' must be a single line") - return v - - -def _check_event_single_line(v: str | None) -> str | None: - return _check_single_line(v, "event") - - -def _check_id_valid(v: str | None) -> str | None: - if v is not None and "\0" in v: - raise ValueError("SSE 'id' must not contain null characters") - return _check_single_line(v, "id") - - -class ServerSentEvent(BaseModel): - """Represents a single Server-Sent Event. - - When `yield`ed from a *path operation function* that uses - `response_class=EventSourceResponse`, each `ServerSentEvent` is encoded - into the [SSE wire format](https://html.spec.whatwg.org/multipage/server-sent-events.html#parsing-an-event-stream) - (`text/event-stream`). - - If you yield a plain object (dict, Pydantic model, etc.) instead, it is - automatically JSON-encoded and sent as the `data:` field. - - All `data` values **including plain strings** are JSON-serialized. - - For example, `data="hello"` produces `data: "hello"` on the wire (with - quotes). - """ - - data: Annotated[ - Any, - Doc( - """ - The event payload. - - Can be any JSON-serializable value: a Pydantic model, dict, list, - string, number, etc. It is **always** serialized to JSON: strings - are quoted (`"hello"` becomes `data: "hello"` on the wire). - - Mutually exclusive with `raw_data`. - """ - ), - ] = None - raw_data: Annotated[ - str | None, - Doc( - """ - Raw string to send as the `data:` field **without** JSON encoding. - - Use this when you need to send pre-formatted text, HTML fragments, - CSV lines, or any non-JSON payload. The string is placed directly - into the `data:` field as-is. - - Mutually exclusive with `data`. - """ - ), - ] = None - event: Annotated[ - str | None, - AfterValidator(_check_event_single_line), - Doc( - """ - Optional event type name. - - Maps to `addEventListener(event, ...)` on the browser. When omitted, - the browser dispatches on the generic `message` event. Must be a - single line. - """ - ), - ] = None - id: Annotated[ - str | None, - AfterValidator(_check_id_valid), - Doc( - """ - Optional event ID. - - The browser sends this value back as the `Last-Event-ID` header on - automatic reconnection. **Must be a single line** and must not contain - null (`\\0`) characters. - """ - ), - ] = None - retry: Annotated[ - int | None, - Field(ge=0), - Doc( - """ - Optional reconnection time in **milliseconds**. - - Tells the browser how long to wait before reconnecting after the - connection is lost. Must be a non-negative integer. - """ - ), - ] = None - comment: Annotated[ - str | None, - Doc( - """ - Optional comment line(s). - - Comment lines start with `:` in the SSE wire format and are ignored by - `EventSource` clients. Useful for keep-alive pings to prevent - proxy/load-balancer timeouts. - """ - ), - ] = None - - @model_validator(mode="after") - def _check_data_exclusive(self) -> "ServerSentEvent": - if self.data is not None and self.raw_data is not None: - raise ValueError( - "Cannot set both 'data' and 'raw_data' on the same " - "ServerSentEvent. Use 'data' for JSON-serialized payloads " - "or 'raw_data' for pre-formatted strings." - ) - return self - - -def format_sse_event( - *, - data_str: Annotated[ - str | None, - Doc( - """ - Pre-serialized data string to use as the `data:` field. - """ - ), - ] = None, - event: Annotated[ - str | None, - Doc( - """ - Optional event type name (`event:` field). - """ - ), - ] = None, - id: Annotated[ - str | None, - Doc( - """ - Optional event ID (`id:` field). - """ - ), - ] = None, - retry: Annotated[ - int | None, - Doc( - """ - Optional reconnection time in milliseconds (`retry:` field). - """ - ), - ] = None, - comment: Annotated[ - str | None, - Doc( - """ - Optional comment line(s) (`:` prefix). - """ - ), - ] = None, -) -> bytes: - """Build SSE wire-format bytes from **pre-serialized** data. - - The result always ends with `\n\n` (the event terminator). - """ - lines: list[str] = [] - - if comment is not None: - for line in comment.splitlines(): - lines.append(f": {line}") - - if event is not None: - lines.append(f"event: {event}") - - if data_str is not None: - for line in data_str.splitlines(): - lines.append(f"data: {line}") - - if id is not None: - lines.append(f"id: {id}") - - if retry is not None: - lines.append(f"retry: {retry}") - - lines.append("") - lines.append("") - return "\n".join(lines).encode("utf-8") - - -# Keep-alive comment, per the SSE spec recommendation -KEEPALIVE_COMMENT = b": ping\n\n" - -# Seconds between keep-alive pings when a generator is idle. -# Private but importable so tests can monkeypatch it. -_PING_INTERVAL: float = 15.0 diff --git a/server/venv/Lib/site-packages/fastapi/staticfiles.py b/server/venv/Lib/site-packages/fastapi/staticfiles.py deleted file mode 100644 index 299015d..0000000 --- a/server/venv/Lib/site-packages/fastapi/staticfiles.py +++ /dev/null @@ -1 +0,0 @@ -from starlette.staticfiles import StaticFiles as StaticFiles # noqa diff --git a/server/venv/Lib/site-packages/fastapi/templating.py b/server/venv/Lib/site-packages/fastapi/templating.py deleted file mode 100644 index 0cb8684..0000000 --- a/server/venv/Lib/site-packages/fastapi/templating.py +++ /dev/null @@ -1 +0,0 @@ -from starlette.templating import Jinja2Templates as Jinja2Templates # noqa diff --git a/server/venv/Lib/site-packages/fastapi/testclient.py b/server/venv/Lib/site-packages/fastapi/testclient.py deleted file mode 100644 index 4012406..0000000 --- a/server/venv/Lib/site-packages/fastapi/testclient.py +++ /dev/null @@ -1 +0,0 @@ -from starlette.testclient import TestClient as TestClient # noqa diff --git a/server/venv/Lib/site-packages/fastapi/types.py b/server/venv/Lib/site-packages/fastapi/types.py deleted file mode 100644 index 1fb86e1..0000000 --- a/server/venv/Lib/site-packages/fastapi/types.py +++ /dev/null @@ -1,12 +0,0 @@ -import types -from collections.abc import Callable -from enum import Enum -from typing import Any, TypeVar, Union - -from pydantic import BaseModel -from pydantic.main import IncEx as IncEx - -DecoratedCallable = TypeVar("DecoratedCallable", bound=Callable[..., Any]) -UnionType = getattr(types, "UnionType", Union) -ModelNameMap = dict[type[BaseModel] | type[Enum], str] -DependencyCacheKey = tuple[Callable[..., Any] | None, tuple[str, ...], str] diff --git a/server/venv/Lib/site-packages/fastapi/utils.py b/server/venv/Lib/site-packages/fastapi/utils.py deleted file mode 100644 index 12eaa2b..0000000 --- a/server/venv/Lib/site-packages/fastapi/utils.py +++ /dev/null @@ -1,136 +0,0 @@ -import re -import warnings -from typing import ( - TYPE_CHECKING, - Any, - Literal, -) - -import fastapi -from fastapi._compat import ( - ModelField, - PydanticSchemaGenerationError, - Undefined, - annotation_is_pydantic_v1, -) -from fastapi.datastructures import DefaultPlaceholder, DefaultType -from fastapi.exceptions import FastAPIDeprecationWarning, PydanticV1NotSupportedError -from pydantic.fields import FieldInfo - -from ._compat import v2 - -if TYPE_CHECKING: # pragma: nocover - from .routing import APIRoute - - -def is_body_allowed_for_status_code(status_code: int | str | None) -> bool: - if status_code is None: - return True - # Ref: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#patterned-fields-1 - if status_code in { - "default", - "1XX", - "2XX", - "3XX", - "4XX", - "5XX", - }: - return True - current_status_code = int(status_code) - return not (current_status_code < 200 or current_status_code in {204, 205, 304}) - - -def get_path_param_names(path: str) -> set[str]: - return set(re.findall("{(.*?)}", path)) - - -_invalid_args_message = ( - "Invalid args for response field! Hint: " - "check that {type_} is a valid Pydantic field type. " - "If you are using a return type annotation that is not a valid Pydantic " - "field (e.g. Union[Response, dict, None]) you can disable generating the " - "response model from the type annotation with the path operation decorator " - "parameter response_model=None. Read more: " - "https://fastapi.tiangolo.com/tutorial/response-model/" -) - - -def create_model_field( - name: str, - type_: Any, - default: Any | None = Undefined, - field_info: FieldInfo | None = None, - alias: str | None = None, - mode: Literal["validation", "serialization"] = "validation", -) -> ModelField: - if annotation_is_pydantic_v1(type_): - raise PydanticV1NotSupportedError( - "pydantic.v1 models are no longer supported by FastAPI." - f" Please update the response model {type_!r}." - ) - field_info = field_info or FieldInfo(annotation=type_, default=default, alias=alias) - try: - return v2.ModelField(mode=mode, name=name, field_info=field_info) - except PydanticSchemaGenerationError: - raise fastapi.exceptions.FastAPIError( - _invalid_args_message.format(type_=type_) - ) from None - - -def generate_operation_id_for_path( - *, name: str, path: str, method: str -) -> str: # pragma: nocover - warnings.warn( - message="fastapi.utils.generate_operation_id_for_path() was deprecated, " - "it is not used internally, and will be removed soon", - category=FastAPIDeprecationWarning, - stacklevel=2, - ) - operation_id = f"{name}{path}" - operation_id = re.sub(r"\W", "_", operation_id) - operation_id = f"{operation_id}_{method.lower()}" - return operation_id - - -def generate_unique_id(route: "APIRoute") -> str: - operation_id = f"{route.name}{route.path_format}" - operation_id = re.sub(r"\W", "_", operation_id) - assert route.methods - operation_id = f"{operation_id}_{list(route.methods)[0].lower()}" - return operation_id - - -def deep_dict_update(main_dict: dict[Any, Any], update_dict: dict[Any, Any]) -> None: - for key, value in update_dict.items(): - if ( - key in main_dict - and isinstance(main_dict[key], dict) - and isinstance(value, dict) - ): - deep_dict_update(main_dict[key], value) - elif ( - key in main_dict - and isinstance(main_dict[key], list) - and isinstance(update_dict[key], list) - ): - main_dict[key] = main_dict[key] + update_dict[key] - else: - main_dict[key] = value - - -def get_value_or_default( - first_item: DefaultPlaceholder | DefaultType, - *extra_items: DefaultPlaceholder | DefaultType, -) -> DefaultPlaceholder | DefaultType: - """ - Pass items or `DefaultPlaceholder`s by descending priority. - - The first one to _not_ be a `DefaultPlaceholder` will be returned. - - Otherwise, the first item (a `DefaultPlaceholder`) will be returned. - """ - items = (first_item,) + extra_items - for item in items: - if not isinstance(item, DefaultPlaceholder): - return item - return first_item diff --git a/server/venv/Lib/site-packages/fastapi/websockets.py b/server/venv/Lib/site-packages/fastapi/websockets.py deleted file mode 100644 index 55a4ac4..0000000 --- a/server/venv/Lib/site-packages/fastapi/websockets.py +++ /dev/null @@ -1,3 +0,0 @@ -from starlette.websockets import WebSocket as WebSocket # noqa -from starlette.websockets import WebSocketDisconnect as WebSocketDisconnect # noqa -from starlette.websockets import WebSocketState as WebSocketState # noqa diff --git a/server/venv/Lib/site-packages/gssapi64.dll b/server/venv/Lib/site-packages/gssapi64.dll deleted file mode 100644 index 408ffb20bdb3ade00326e4000f7c0c5a5d08a1b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 412800 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